Linux bluetooth development
 help / color / mirror / Atom feed
* Re: Bluetooth: btusb: Add VID/PID 0489:e156 for MediaTek MT7902
From: Kirill Shubin @ 2026-05-03  8:43 UTC (permalink / raw)
  To: Sean Wang
  Cc: sean.wang, luiz.von.dentz, linux-bluetooth,
	moderated list:ARM/Mediatek SoC support
In-Reply-To: <CAGp9LzqXKwJf7=bFuv_gW9yFH7uBuXva398TC=XOrZkyd-ermQ@mail.gmail.com>

Hi Sean,

On Sat, May 2, 2026, Sean Wang wrote:
> Could you help get the USB device information from your test machine
> as the following and reply to the mail?

Sure, here is the full information for 0489:e156 from
/sys/kernel/debug/usb/devices:

T:  Bus=01 Lev=01 Prnt=01 Port=09 Cnt=05 Dev#=  6 Spd=480  MxCh= 0
D:  Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=0489 ProdID=e156 Rev= 1.00
S:  Manufacturer=MediaTek Inc.
S:  Product=Wireless_Device
S:  SerialNumber=000000000
C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA
A:  FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01
I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=125us
E:  Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
I:  If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
I:  If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
I:  If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
I:  If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
I:  If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
I:  If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  63 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  63 Ivl=1ms
I:  If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=8a(I) Atr=03(Int.) MxPS=  64 Ivl=125us
E:  Ad=0a(O) Atr=03(Int.) MxPS=  64 Ivl=125us
I:* If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=8a(I) Atr=03(Int.) MxPS= 512 Ivl=125us
E:  Ad=0a(O) Atr=03(Int.) MxPS= 512 Ivl=125us

> I will send the patch including the VID/PID
> thanks

Thanks for your help!

Best regards,
Kirill Shubin


вс, 3 мая 2026 г. в 02:17, Sean Wang <sean.wang@kernel.org>:
>
> Hi Кирилл,
>
> Could you help get the USB device information from your test machine
> as the following and reply to the mail?
>
> The information in /sys/kernel/debug/usb/devices about the Bluetooth
> device is listed as the below.
>
> T:  Bus=07 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=480  MxCh= 0
> D:  Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs=  1
> P:  Vendor=13d3 ProdID=3596 Rev= 1.00
> S:  Manufacturer=MediaTek Inc.
> S:  Product=Wireless_Device
> S:  SerialNumber=000000000
> C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA
> A:  FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01
> I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=125us
> E:  Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
> E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
> I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
> I:  If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
> I:  If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
> I:  If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
> I:  If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
> I:  If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
> I:  If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=  63 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=  63 Ivl=1ms
> I:* If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
> E:  Ad=8a(I) Atr=03(Int.) MxPS=  64 Ivl=125us
> E:  Ad=0a(O) Atr=03(Int.) MxPS=  64 Ivl=125us
> I:  If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
> E:  Ad=8a(I) Atr=03(Int.) MxPS= 512 Ivl=125us
> E:  Ad=0a(O) Atr=03(Int.) MxPS= 512 Ivl=125us
>
> I will send the patch including the VID/PID
> thanks
>
> On Sat, May 2, 2026 at 12:20 PM Кирилл <kirill.kz.902@gmail.com> wrote:
> >
> > Hi Sean,
> >
> > Following your MT7902 series, here is one more VID/PID variant
> > that is currently not recognized by btusb: 0489:e156 (Foxconn).
> >
> > Adding the entry below makes Bluetooth work on v7.1-rc1:
> >
> >   /* Additional MediaTek MT7902 Bluetooth devices */
> >   { USB_DEVICE(0x0489, 0xe156), .driver_info = BTUSB_MEDIATEK |
> >                                                BTUSB_WIDEBAND_SPEECH },
> >
> > dmesg after loading the patched module:
> >
> >   Bluetooth: hci0: HW/SW Version: 0x008a008a,
> >                    Build Time: 20250826211444
> >
> > /sys/kernel/debug/usb/devices:
> >
> >   T:  Bus=01 Lev=01 Prnt=01 Port=09 Cnt=05 Dev#=6 Spd=480 MxCh=0
> >   D:  Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs=1
> >   P:  Vendor=0489 ProdID=e156 Rev= 1.00
> >   S:  Manufacturer=MediaTek Inc.
> >   S:  Product=Wireless_Device
> >   C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA
> >
> > Could you include this VID/PID in the next MT7902 round?
> >
> > Tested-by: Kirill Shubin <kirill.kz.902@gmail.com>
> >
> > Thanks,
> > Kirill
> >

^ permalink raw reply

* [bluez/bluez]
From: BluezTestBot @ 2026-05-03  6:34 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1076781
  Home:   https://github.com/bluez/bluez

To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications

^ permalink raw reply

* RE: [bluetooth-next,v2] bluetooth: remove all PCMCIA drivers
From: bluez.test.bot @ 2026-05-03  5:30 UTC (permalink / raw)
  To: linux-bluetooth, enelsonmoore
In-Reply-To: <20260503033201.19719-1-enelsonmoore@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 4773 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1088873

---Test result---

Test Summary:
CheckPatch                    FAIL      2.54 seconds
GitLint                       FAIL      0.23 seconds
SubjectPrefix                 FAIL      0.08 seconds
BuildKernel                   PASS      26.12 seconds
CheckAllWarning               PASS      29.00 seconds
CheckSparse                   PASS      27.51 seconds
BuildKernel32                 PASS      25.41 seconds
TestRunnerSetup               PASS      573.71 seconds
TestRunner_l2cap-tester       FAIL      6.60 seconds
TestRunner_iso-tester         PASS      295.80 seconds
TestRunner_bnep-tester        FAIL      6.69 seconds
TestRunner_mgmt-tester        FAIL      8.93 seconds
TestRunner_rfcomm-tester      PASS      29.00 seconds
TestRunner_sco-tester         PASS      66.20 seconds
TestRunner_ioctl-tester       FAIL      37.46 seconds
TestRunner_mesh-tester        PASS      27.03 seconds
TestRunner_smp-tester         PASS      6.68 seconds
TestRunner_userchan-tester    FAIL      6.77 seconds
TestRunner_6lowpan-tester     PASS      23.02 seconds
IncrementalBuild              PASS      25.68 seconds

Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[bluetooth-next,v2] bluetooth: remove all PCMCIA drivers
WARNING: Prefer a maximum 75 chars per line (possible unwrapped commit description?)
#135: 
[1] https://lore.kernel.org/all/c5b39544-a4fb-4796-a046-0b9be9853787@app.fastmail.com/

WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#309: 
deleted file mode 100644

total: 0 errors, 2 warnings, 109 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/patch/14551781.patch has style problems, please review.

NOTE: Ignored message types: UNKNOWN_COMMIT_ID

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.


##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[bluetooth-next,v2] bluetooth: remove all PCMCIA drivers

WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
24: B1 Line exceeds max length (86>80): "[1] https://lore.kernel.org/all/c5b39544-a4fb-4796-a046-0b9be9853787@app.fastmail.com/"
##############################
Test: SubjectPrefix - FAIL
Desc: Check subject contains "Bluetooth" prefix
Output:
"Bluetooth: " prefix is not specified in the subject
##############################
Test: TestRunner_l2cap-tester - FAIL
Desc: Run l2cap-tester with test-runner
Output:
No test result found
##############################
Test: TestRunner_bnep-tester - FAIL
Desc: Run bnep-tester with test-runner
Output:
No test result found
##############################
Test: TestRunner_mgmt-tester - FAIL
Desc: Run mgmt-tester with test-runner
Output:
No test result found
##############################
Test: TestRunner_ioctl-tester - FAIL
Desc: Run ioctl-tester with test-runner
Output:
Total: 28, Passed: 0 (0.0%), Failed: 11, Not Run: 17

Failed Test Cases
Device List                                          Timed out  -30.832 seconds
Device Info                                          Timed out   -6.180 seconds
Reset Stat                                           Timed out   -6.183 seconds
Set Link Mode - ACCEPT                               Timed out   -6.186 seconds
Set Pkt Type - DM                                    Timed out  -14.376 seconds
Set Pkt Type - DH                                    Timed out  -14.379 seconds
Set Pkt Type - HV                                    Timed out  -14.382 seconds
Set Pkt Type - 2-DH                                  Timed out  -14.385 seconds
Set Pkt Type - 2-DH                                  Timed out  -14.389 seconds
Set Pkt Type - ALL                                   Timed out  -14.392 seconds
Set ACL MTU - 1                                      Timed out  -14.395 seconds
##############################
Test: TestRunner_userchan-tester - FAIL
Desc: Run userchan-tester with test-runner
Output:
No test result found


https://github.com/bluez/bluetooth-next/pull/141

---
Regards,
Linux Bluetooth


^ permalink raw reply

* Security: sdp_extract_seqtype() signed/unsigned confusion → OOB heap read (no pairing required, 8.1H)
From: admin @ 2026-05-03  4:02 UTC (permalink / raw)
  To: linux-bluetooth@vger.kernel.org

  To: linux-bluetooth@vger.kernel.org                                                                                                                    
  Subject: Security: sdp_extract_seqtype() signed/unsigned confusion → OOB heap read (no pairing required, 8.1H)

  Hi Marcel,                                

  Reporting a vulnerability in BlueZ lib/sdp.c.                                                                                                          

  File: lib/sdp.c:1262 — sdp_extract_seqtype()                                                                                                            
  CVSS: 8.1H (AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H)

  SDP_SEQ32 stores a uint32_t data length into a signed int* with no overflow check. Value 0x80000000 becomes INT_MIN. Downstream at extract_seq()        
  (sdp.c:1392) and sdp_extract_pdu() (sdp-client.c:174) that signed value is used as a length/offset → OOB heap read.                                    

  Trigger: Crafted SDP response from a malicious Bluetooth device. No pairing required. Bluetooth adjacency (~10m), passive service discovery path.      

  Fix: Use uint32_t throughout the SDP sequence extraction chain, or add explicit overflow check before assigning to int*.                                

  Please let me know if you need a PoC.

Martin Brodeur Ottawa Canada

^ permalink raw reply

* [PATCH bluetooth-next v2] bluetooth: remove all PCMCIA drivers
From: Ethan Nelson-Moore @ 2026-05-03  3:31 UTC (permalink / raw)
  To: linux-mips, linux-bluetooth
  Cc: Ethan Nelson-Moore, Russell King, Huacai Chen, WANG Xuerui,
	Thomas Bogendoerfer, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Marcel Holtmann,
	Luiz Augusto von Dentz, Eric Biggers, Ard Biesheuvel, Herbert Xu,
	Theodore Ts'o, André Draszik, Geert Uytterhoeven,
	Jakub Kicinski, Simon Horman, Johan Korsnes, David Heidelberg

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>
---
This patch is identical to my previous RFC patch, but rebased on
the latest bluetooth-next tree.

 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 -
 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 c51ae373ca88..78942ebe3fc2 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 f116a01c3f5f..8f8a058294fb 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 d5ef396dffe3..f319c880127c 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 cba4cdff5acd..ffa8ae26d713 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 3629afbe5d75..aec719b1b193 100644
--- a/arch/mips/configs/mtx1_defconfig
+++ b/arch/mips/configs/mtx1_defconfig
@@ -184,9 +184,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 ccabc6e17168..7f4f8ff3965c 100644
--- a/arch/powerpc/configs/ppc6xx_defconfig
+++ b/arch/powerpc/configs/ppc6xx_defconfig
@@ -282,9 +282,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 fc1b37044a9b..4e8c24d757e9 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);
-- 
2.43.0


^ permalink raw reply related

* Re: Bluetooth: btusb: Add VID/PID 0489:e156 for MediaTek MT7902
From: Sean Wang @ 2026-05-02 23:17 UTC (permalink / raw)
  To: Кирилл
  Cc: sean.wang, luiz.von.dentz, linux-bluetooth,
	moderated list:ARM/Mediatek SoC support
In-Reply-To: <CAL2ecxgBeZNSSuwJROmuvGFsajjpxqV1+LYnoz5dYGUPA30HeA@mail.gmail.com>

Hi Кирилл,

Could you help get the USB device information from your test machine
as the following and reply to the mail?

The information in /sys/kernel/debug/usb/devices about the Bluetooth
device is listed as the below.

T:  Bus=07 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=480  MxCh= 0
D:  Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=13d3 ProdID=3596 Rev= 1.00
S:  Manufacturer=MediaTek Inc.
S:  Product=Wireless_Device
S:  SerialNumber=000000000
C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA
A:  FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01
I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=125us
E:  Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
I:  If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
I:  If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
I:  If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
I:  If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
I:  If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
I:  If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  63 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  63 Ivl=1ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
E:  Ad=8a(I) Atr=03(Int.) MxPS=  64 Ivl=125us
E:  Ad=0a(O) Atr=03(Int.) MxPS=  64 Ivl=125us
I:  If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none)
E:  Ad=8a(I) Atr=03(Int.) MxPS= 512 Ivl=125us
E:  Ad=0a(O) Atr=03(Int.) MxPS= 512 Ivl=125us

I will send the patch including the VID/PID
thanks

On Sat, May 2, 2026 at 12:20 PM Кирилл <kirill.kz.902@gmail.com> wrote:
>
> Hi Sean,
>
> Following your MT7902 series, here is one more VID/PID variant
> that is currently not recognized by btusb: 0489:e156 (Foxconn).
>
> Adding the entry below makes Bluetooth work on v7.1-rc1:
>
>   /* Additional MediaTek MT7902 Bluetooth devices */
>   { USB_DEVICE(0x0489, 0xe156), .driver_info = BTUSB_MEDIATEK |
>                                                BTUSB_WIDEBAND_SPEECH },
>
> dmesg after loading the patched module:
>
>   Bluetooth: hci0: HW/SW Version: 0x008a008a,
>                    Build Time: 20250826211444
>
> /sys/kernel/debug/usb/devices:
>
>   T:  Bus=01 Lev=01 Prnt=01 Port=09 Cnt=05 Dev#=6 Spd=480 MxCh=0
>   D:  Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs=1
>   P:  Vendor=0489 ProdID=e156 Rev= 1.00
>   S:  Manufacturer=MediaTek Inc.
>   S:  Product=Wireless_Device
>   C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA
>
> Could you include this VID/PID in the next MT7902 round?
>
> Tested-by: Kirill Shubin <kirill.kz.902@gmail.com>
>
> Thanks,
> Kirill
>

^ permalink raw reply

* RE: [v2] Bluetooth: HIDP: serialise l2cap_unregister_user via hidp_session_sem
From: bluez.test.bot @ 2026-05-02 17:44 UTC (permalink / raw)
  To: linux-bluetooth, michael.bommarito
In-Reply-To: <20260502164303.2299816-1-michael.bommarito@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 3741 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1088829

---Test result---

Test Summary:
CheckPatch                    PASS      0.64 seconds
GitLint                       FAIL      0.24 seconds
SubjectPrefix                 PASS      0.09 seconds
BuildKernel                   PASS      28.18 seconds
CheckAllWarning               PASS      30.05 seconds
CheckSparse                   PASS      28.76 seconds
BuildKernel32                 PASS      26.27 seconds
TestRunnerSetup               PASS      579.48 seconds
TestRunner_l2cap-tester       FAIL      6.77 seconds
TestRunner_iso-tester         PASS      295.82 seconds
TestRunner_bnep-tester        FAIL      6.75 seconds
TestRunner_mgmt-tester        FAIL      8.99 seconds
TestRunner_rfcomm-tester      PASS      29.07 seconds
TestRunner_sco-tester         PASS      68.13 seconds
TestRunner_ioctl-tester       FAIL      37.43 seconds
TestRunner_mesh-tester        PASS      27.11 seconds
TestRunner_smp-tester         PASS      6.58 seconds
TestRunner_userchan-tester    FAIL      6.68 seconds
TestRunner_6lowpan-tester     PASS      22.83 seconds
IncrementalBuild              PASS      25.14 seconds

Details
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[v2] Bluetooth: HIDP: serialise l2cap_unregister_user via hidp_session_sem

WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
42: B1 Line exceeds max length (86>80): "Link: https://lore.kernel.org/all/20260422011437.176643-1-michael.bommarito@gmail.com/"
##############################
Test: TestRunner_l2cap-tester - FAIL
Desc: Run l2cap-tester with test-runner
Output:
No test result found
##############################
Test: TestRunner_bnep-tester - FAIL
Desc: Run bnep-tester with test-runner
Output:
No test result found
##############################
Test: TestRunner_mgmt-tester - FAIL
Desc: Run mgmt-tester with test-runner
Output:
No test result found
##############################
Test: TestRunner_ioctl-tester - FAIL
Desc: Run ioctl-tester with test-runner
Output:
Total: 28, Passed: 0 (0.0%), Failed: 11, Not Run: 17

Failed Test Cases
Device List                                          Timed out  -30.849 seconds
Device Info                                          Timed out   -6.201 seconds
Reset Stat                                           Timed out   -6.204 seconds
Set Link Mode - ACCEPT                               Timed out   -6.207 seconds
Set Pkt Type - DM                                    Timed out  -14.394 seconds
Set Pkt Type - DH                                    Timed out  -14.397 seconds
Set Pkt Type - HV                                    Timed out  -14.400 seconds
Set Pkt Type - 2-DH                                  Timed out  -14.403 seconds
Set Pkt Type - 2-DH                                  Timed out  -14.406 seconds
Set Pkt Type - ALL                                   Timed out  -14.409 seconds
Set ACL MTU - 1                                      Timed out  -14.411 seconds
##############################
Test: TestRunner_userchan-tester - FAIL
Desc: Run userchan-tester with test-runner
Output:
No test result found


https://github.com/bluez/bluetooth-next/pull/140

---
Regards,
Linux Bluetooth


^ permalink raw reply

* Bluetooth: btusb: Add VID/PID 0489:e156 for MediaTek MT7902
From: Кирилл @ 2026-05-02 17:20 UTC (permalink / raw)
  To: sean.wang; +Cc: luiz.von.dentz, linux-bluetooth

Hi Sean,

Following your MT7902 series, here is one more VID/PID variant
that is currently not recognized by btusb: 0489:e156 (Foxconn).

Adding the entry below makes Bluetooth work on v7.1-rc1:

  /* Additional MediaTek MT7902 Bluetooth devices */
  { USB_DEVICE(0x0489, 0xe156), .driver_info = BTUSB_MEDIATEK |
                                               BTUSB_WIDEBAND_SPEECH },

dmesg after loading the patched module:

  Bluetooth: hci0: HW/SW Version: 0x008a008a,
                   Build Time: 20250826211444

/sys/kernel/debug/usb/devices:

  T:  Bus=01 Lev=01 Prnt=01 Port=09 Cnt=05 Dev#=6 Spd=480 MxCh=0
  D:  Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs=1
  P:  Vendor=0489 ProdID=e156 Rev= 1.00
  S:  Manufacturer=MediaTek Inc.
  S:  Product=Wireless_Device
  C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA

Could you include this VID/PID in the next MT7902 round?

Tested-by: Kirill Shubin <kirill.kz.902@gmail.com>

Thanks,
Kirill

^ permalink raw reply

* [bluetooth-next:master] BUILD SUCCESS f2f6f881510396c54bc2e4391d3c4067fbdfdd25
From: kernel test robot @ 2026-05-02 16:47 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master
branch HEAD: f2f6f881510396c54bc2e4391d3c4067fbdfdd25  Bluetooth: SMP: Use AES-CMAC library API

elapsed time: 2684m

configs tested: 173
configs skipped: 2

The following configs have been built successfully.
More configs may be tested in the coming days.

tested configs:
alpha                             allnoconfig    gcc-15.2.0
alpha                            allyesconfig    gcc-15.2.0
alpha                               defconfig    gcc-15.2.0
arc                              allmodconfig    clang-16
arc                               allnoconfig    gcc-15.2.0
arc                              allyesconfig    clang-23
arc                                 defconfig    gcc-15.2.0
arc                            randconfig-001    gcc-8.5.0
arc                   randconfig-001-20260502    gcc-8.5.0
arc                            randconfig-002    gcc-8.5.0
arc                   randconfig-002-20260502    gcc-8.5.0
arm                               allnoconfig    gcc-15.2.0
arm                              allyesconfig    clang-16
arm                                 defconfig    gcc-15.2.0
arm                            randconfig-001    gcc-8.5.0
arm                   randconfig-001-20260502    gcc-8.5.0
arm                            randconfig-002    gcc-8.5.0
arm                   randconfig-002-20260502    gcc-8.5.0
arm                            randconfig-003    gcc-8.5.0
arm                   randconfig-003-20260502    gcc-8.5.0
arm                            randconfig-004    gcc-8.5.0
arm                   randconfig-004-20260502    gcc-8.5.0
arm64                            allmodconfig    clang-23
arm64                             allnoconfig    gcc-15.2.0
arm64                               defconfig    gcc-15.2.0
arm64                          randconfig-001    gcc-10.5.0
arm64                 randconfig-001-20260502    gcc-10.5.0
arm64                          randconfig-002    gcc-10.5.0
arm64                 randconfig-002-20260502    gcc-10.5.0
arm64                          randconfig-003    gcc-10.5.0
arm64                 randconfig-003-20260502    gcc-10.5.0
arm64                          randconfig-004    gcc-10.5.0
arm64                 randconfig-004-20260502    gcc-10.5.0
csky                             allmodconfig    gcc-15.2.0
csky                              allnoconfig    gcc-15.2.0
csky                                defconfig    gcc-15.2.0
csky                           randconfig-001    gcc-10.5.0
csky                  randconfig-001-20260502    gcc-10.5.0
csky                           randconfig-002    gcc-10.5.0
csky                  randconfig-002-20260502    gcc-10.5.0
hexagon                          allmodconfig    gcc-15.2.0
hexagon                           allnoconfig    gcc-15.2.0
hexagon                             defconfig    gcc-15.2.0
hexagon               randconfig-001-20260502    clang-23
hexagon               randconfig-002-20260502    clang-23
i386                             allmodconfig    clang-20
i386                              allnoconfig    gcc-15.2.0
i386                             allyesconfig    clang-20
i386        buildonly-randconfig-001-20260502    gcc-14
i386        buildonly-randconfig-002-20260502    gcc-14
i386        buildonly-randconfig-003-20260502    gcc-14
i386        buildonly-randconfig-004-20260502    gcc-14
i386        buildonly-randconfig-005-20260502    gcc-14
i386        buildonly-randconfig-006-20260502    gcc-14
i386                                defconfig    gcc-15.2.0
loongarch                        allmodconfig    clang-23
loongarch                         allnoconfig    gcc-15.2.0
loongarch                           defconfig    clang-19
loongarch             randconfig-001-20260502    clang-23
loongarch             randconfig-002-20260502    clang-23
m68k                             allmodconfig    gcc-15.2.0
m68k                              allnoconfig    gcc-15.2.0
m68k                             allyesconfig    clang-16
m68k                                defconfig    clang-19
m68k                        mvme147_defconfig    gcc-15.2.0
microblaze                        allnoconfig    gcc-15.2.0
microblaze                       allyesconfig    gcc-15.2.0
microblaze                          defconfig    clang-19
mips                             allmodconfig    gcc-15.2.0
mips                              allnoconfig    gcc-15.2.0
mips                             allyesconfig    gcc-15.2.0
nios2                            allmodconfig    clang-23
nios2                             allnoconfig    clang-23
nios2                               defconfig    clang-19
nios2                 randconfig-001-20260502    clang-23
nios2                 randconfig-002-20260502    clang-23
openrisc                         allmodconfig    clang-23
openrisc                          allnoconfig    clang-23
openrisc                            defconfig    gcc-15.2.0
parisc                           allmodconfig    gcc-15.2.0
parisc                            allnoconfig    clang-23
parisc                           allyesconfig    clang-19
parisc                              defconfig    gcc-15.2.0
parisc                         randconfig-001    gcc-12.5.0
parisc                randconfig-001-20260502    gcc-12.5.0
parisc                         randconfig-002    gcc-12.5.0
parisc                randconfig-002-20260502    gcc-12.5.0
parisc64                            defconfig    clang-19
powerpc                          allmodconfig    gcc-15.2.0
powerpc                           allnoconfig    clang-23
powerpc                        randconfig-001    gcc-12.5.0
powerpc               randconfig-001-20260502    gcc-12.5.0
powerpc                        randconfig-002    gcc-12.5.0
powerpc               randconfig-002-20260502    gcc-12.5.0
powerpc64                      randconfig-001    gcc-12.5.0
powerpc64             randconfig-001-20260502    gcc-12.5.0
powerpc64                      randconfig-002    gcc-12.5.0
powerpc64             randconfig-002-20260502    gcc-12.5.0
riscv                            allmodconfig    clang-23
riscv                             allnoconfig    clang-23
riscv                            allyesconfig    clang-16
riscv                               defconfig    gcc-15.2.0
riscv                 randconfig-001-20260502    gcc-14.3.0
riscv                 randconfig-002-20260502    gcc-14.3.0
s390                             allmodconfig    clang-19
s390                              allnoconfig    clang-23
s390                             allyesconfig    gcc-15.2.0
s390                                defconfig    gcc-15.2.0
s390                  randconfig-001-20260502    gcc-14.3.0
s390                  randconfig-002-20260502    gcc-14.3.0
sh                               allmodconfig    gcc-15.2.0
sh                                allnoconfig    clang-23
sh                               allyesconfig    clang-19
sh                                  defconfig    gcc-14
sh                    randconfig-001-20260502    gcc-14.3.0
sh                    randconfig-002-20260502    gcc-14.3.0
sh                      rts7751r2d1_defconfig    gcc-15.2.0
sparc                             allnoconfig    clang-23
sparc                               defconfig    gcc-15.2.0
sparc                 randconfig-001-20260502    gcc-8.5.0
sparc                 randconfig-002-20260502    gcc-8.5.0
sparc64                          allmodconfig    clang-23
sparc64                             defconfig    gcc-14
sparc64               randconfig-001-20260502    gcc-8.5.0
sparc64               randconfig-002-20260502    gcc-8.5.0
um                               allmodconfig    clang-19
um                                allnoconfig    clang-23
um                               allyesconfig    gcc-15.2.0
um                                  defconfig    gcc-14
um                             i386_defconfig    gcc-14
um                    randconfig-001-20260502    gcc-8.5.0
um                    randconfig-002-20260502    gcc-8.5.0
um                           x86_64_defconfig    gcc-14
x86_64                           allmodconfig    clang-20
x86_64                            allnoconfig    clang-23
x86_64                           allyesconfig    clang-20
x86_64               buildonly-randconfig-001    clang-20
x86_64      buildonly-randconfig-001-20260502    clang-20
x86_64               buildonly-randconfig-002    clang-20
x86_64      buildonly-randconfig-002-20260502    clang-20
x86_64               buildonly-randconfig-003    clang-20
x86_64      buildonly-randconfig-003-20260502    clang-20
x86_64               buildonly-randconfig-004    clang-20
x86_64      buildonly-randconfig-004-20260502    clang-20
x86_64               buildonly-randconfig-005    clang-20
x86_64      buildonly-randconfig-005-20260502    clang-20
x86_64               buildonly-randconfig-006    clang-20
x86_64      buildonly-randconfig-006-20260502    clang-20
x86_64                              defconfig    gcc-14
x86_64                                  kexec    clang-20
x86_64                randconfig-001-20260502    clang-20
x86_64                randconfig-002-20260502    clang-20
x86_64                randconfig-003-20260502    clang-20
x86_64                randconfig-004-20260502    clang-20
x86_64                randconfig-005-20260502    clang-20
x86_64                randconfig-006-20260502    clang-20
x86_64                randconfig-071-20260502    gcc-14
x86_64                randconfig-072-20260502    gcc-14
x86_64                randconfig-073-20260502    gcc-14
x86_64                randconfig-074-20260502    gcc-14
x86_64                randconfig-075-20260502    gcc-14
x86_64                randconfig-076-20260502    gcc-14
x86_64                               rhel-9.4    clang-20
x86_64                           rhel-9.4-bpf    gcc-14
x86_64                          rhel-9.4-func    clang-20
x86_64                    rhel-9.4-kselftests    clang-20
x86_64                         rhel-9.4-kunit    gcc-14
x86_64                           rhel-9.4-ltp    gcc-14
x86_64                          rhel-9.4-rust    clang-20
xtensa                            allnoconfig    clang-23
xtensa                           allyesconfig    clang-23
xtensa                randconfig-001-20260502    gcc-8.5.0
xtensa                randconfig-002-20260502    gcc-8.5.0

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply

* [PATCH v2] Bluetooth: HIDP: serialise l2cap_unregister_user via hidp_session_sem
From: Michael Bommarito @ 2026-05-02 16:43 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Luiz Augusto von Dentz, Pauli Virtanen, linux-bluetooth,
	linux-kernel
In-Reply-To: <20260422011437.176643-1-michael.bommarito@gmail.com>

Commit dbf666e4fc9b ("Bluetooth: HIDP: Fix possible UAF") made
hidp_session_remove() drop the L2CAP reference and set
session->conn = NULL once the session is considered removed, and
added a bare if (session->conn) guard around the kthread-exit
l2cap_unregister_user() call in hidp_session_thread().  The sibling
ioctl site in hidp_connection_del() still reads session->conn
unlocked and unguarded, and the kthread-exit guard itself is a
lockless double-read.

hidp_session_find() drops hidp_session_sem before returning, so
hidp_session_remove() can null session->conn between the lookup and
the call in hidp_connection_del().  Worse, since commit 752a6c9596dd
("Bluetooth: L2CAP: Fix use-after-free in l2cap_unregister_user")
takes mutex_lock(&conn->lock) inside l2cap_unregister_user(), a
stale non-NULL snapshot also UAFs on conn->lock.  v1 only added an
if (session->conn) guard at the ioctl site, which doesn't address
either race; Luiz suggested snapshotting session->conn under the
sem and clearing it before the call.

Taking hidp_session_sem across l2cap_unregister_user() would be
wrong: l2cap_conn_del() already establishes the lock order

  conn->lock -> hidp_session_sem

via l2cap_unregister_all_users() -> user->remove ==
hidp_session_remove(), so taking hidp_session_sem before conn->lock
would AB/BA deadlock.

Factor a helper hidp_session_unregister_conn() that under
down_write(&hidp_session_sem) snapshots session->conn and clears
the member, then outside the sem calls l2cap_unregister_user() and
l2cap_conn_put() on the snapshot.  Call it from both
hidp_connection_del() and hidp_session_thread()'s exit path.  At
most one consumer wins the write-sem; later callers observe
session->conn == NULL and skip the unregister and put, so the
reference hidp_session_new() took via l2cap_conn_get() is consumed
exactly once.  session_free() already tolerates a NULL session->conn.

Fixes: dbf666e4fc9b ("Bluetooth: HIDP: Fix possible UAF")
Suggested-by: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Link: https://lore.kernel.org/all/20260422011437.176643-1-michael.bommarito@gmail.com/
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Assisted-by: Claude:claude-opus-4-7
---
Tested under UML with CONFIG_BT_HIDP=y, CONFIG_KASAN=y, and
CONFIG_PROVE_LOCKING=y.  W=1 build of net/bluetooth/hidp/ clean;
boot clean.  A KCFLAGS-gated test stub (not part of this patch)
drove hidp_session_unregister_conn() twice in a row against a fake
session with conn = NULL: the helper short-circuited both times and
lockdep stayed silent.

 net/bluetooth/hidp/core.c | 27 ++++++++++++++++++++++++---
 1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 7bcf8c5ceaee..976f91eeb745 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -1035,6 +1035,28 @@ static struct hidp_session *hidp_session_find(const bdaddr_t *bdaddr)
 	return session;
 }
 
+/*
+ * Consume session->conn: clear the member under hidp_session_sem, then
+ * l2cap_unregister_user() and l2cap_conn_put() the snapshot outside the
+ * sem.  At most one caller wins; later callers see NULL and skip.  The
+ * reference is the one hidp_session_new() took via l2cap_conn_get().
+ */
+static void hidp_session_unregister_conn(struct hidp_session *session)
+{
+	struct l2cap_conn *conn;
+
+	down_write(&hidp_session_sem);
+	conn = session->conn;
+	if (conn)
+		session->conn = NULL;
+	up_write(&hidp_session_sem);
+
+	if (conn) {
+		l2cap_unregister_user(conn, &session->user);
+		l2cap_conn_put(conn);
+	}
+}
+
 /*
  * Start session synchronously
  * This starts a session thread and waits until initialization
@@ -1311,8 +1333,7 @@ static int hidp_session_thread(void *arg)
 	 * Instead, this call has the same semantics as if user-space tried to
 	 * delete the session.
 	 */
-	if (session->conn)
-		l2cap_unregister_user(session->conn, &session->user);
+	hidp_session_unregister_conn(session);
 
 	hidp_session_put(session);
 
@@ -1418,7 +1439,7 @@ int hidp_connection_del(struct hidp_conndel_req *req)
 				         HIDP_CTRL_VIRTUAL_CABLE_UNPLUG,
 				       NULL, 0);
 	else
-		l2cap_unregister_user(session->conn, &session->user);
+		hidp_session_unregister_conn(session);
 
 	hidp_session_put(session);
 
-- 
2.53.0


^ permalink raw reply related

* [syzbot] Monthly bluetooth report (May 2026)
From: syzbot @ 2026-05-02 12:32 UTC (permalink / raw)
  To: linux-bluetooth, linux-kernel, luiz.dentz, marcel, syzkaller-bugs

Hello bluetooth maintainers/developers,

This is a 31-day syzbot report for the bluetooth subsystem.
All related reports/information can be found at:
https://syzkaller.appspot.com/upstream/s/bluetooth

During the period, 3 new issues were detected and 0 were fixed.
In total, 32 issues are still open and 101 have already been fixed.

Some of the still happening issues:

Ref  Crashes Repro Title
<1>  13915   Yes   WARNING in hci_conn_timeout (2)
                   https://syzkaller.appspot.com/bug?extid=fc4b5b2477d4ca272907
<2>  8770    Yes   WARNING in call_timer_fn
                   https://syzkaller.appspot.com/bug?extid=6fb78d577e89e69602f9
<3>  4488    Yes   general protection fault in lock_sock_nested
                   https://syzkaller.appspot.com/bug?extid=d3ccfb78a0dc16ffebe3
<4>  1766    No    KASAN: vmalloc-out-of-bounds Read in kcov_remote_start
                   https://syzkaller.appspot.com/bug?extid=8a173e13208949931dc7
<5>  524     Yes   WARNING: ODEBUG bug in hci_release_dev (2)
                   https://syzkaller.appspot.com/bug?extid=b170dbf55520ebf5969a
<6>  358     No    WARNING in l2cap_chan_del
                   https://syzkaller.appspot.com/bug?extid=3272785b7a1fc9b510f6
<7>  295     Yes   KASAN: wild-memory-access Read in l2cap_connect_cfm
                   https://syzkaller.appspot.com/bug?extid=0e4ebcc970728e056324
<8>  217     Yes   WARNING in hci_recv_frame
                   https://syzkaller.appspot.com/bug?extid=3e07a461b836821ff70e
<9>  163     Yes   KASAN: slab-use-after-free Read in l2cap_sock_new_connection_cb
                   https://syzkaller.appspot.com/bug?extid=cdae834448ec8c3602fe
<10> 135     Yes   KASAN: slab-use-after-free Read in bt_accept_unlink
                   https://syzkaller.appspot.com/bug?extid=a1595e656a83ea5b78eb

---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.

To disable reminders for individual bugs, reply with the following command:
#syz set <Ref> no-reminders

To change bug's subsystems, reply with:
#syz set <Ref> subsystems: new-subsystem

You may send multiple commands in a single email message.

^ permalink raw reply

* [bluez/bluez]
From: BluezTestBot @ 2026-05-02  9:11 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1076276
  Home:   https://github.com/bluez/bluez

To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications

^ permalink raw reply

* [Bug 221449] Wireless gamepad stopped working through Bluetooth
From: bugzilla-daemon @ 2026-05-01 23:36 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <bug-221449-62941@https.bugzilla.kernel.org/>

https://bugzilla.kernel.org/show_bug.cgi?id=221449

--- Comment #1 from Arvin Ignaci (arvin.ignaci@gmail.com) ---
To clarify, the gamepad stopped working after a system update, which is why I
suspected a kernel regression and posted this issue here.

-- 
You may reply to this email to add a comment.

You are receiving this mail because:
You are the assignee for the bug.

^ permalink raw reply

* [Bug 221449] New: Wireless gamepad stopped working through Bluetooth
From: bugzilla-daemon @ 2026-05-01 22:37 UTC (permalink / raw)
  To: linux-bluetooth

https://bugzilla.kernel.org/show_bug.cgi?id=221449

            Bug ID: 221449
           Summary: Wireless gamepad stopped working through Bluetooth
           Product: Drivers
           Version: 2.5
          Hardware: Intel
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P3
         Component: Bluetooth
          Assignee: linux-bluetooth@vger.kernel.org
          Reporter: arvin.ignaci@gmail.com
        Regression: No

I'm running Fedora Silverblue 44 (Universal Blue image) with kernel version
6.19.14. Some time in the last month or so, a Bluetooth gamepad I had stopped
working. It started with inputs being mapped incorrectly and certain inputs not
being recognized. Now, I don't get any input at all. The same gamepad used to
work just fine over Bluetooth and still works over USB.

The gamepad is a GuliKit KK3 set to the "Android" pairing mode; It shows up as
an "Xbox Wireless Controller" in Linux. My Bluetooth controller appears to be
an Intel AX200 modem (according to lsusb). When I connect the gamepad via
Bluetooth and try pressing some buttons or moving the sticks around, the dmesg
output is filled with these messages:

> [ 2041.273972] hid_report_raw_event: 14 callbacks suppressed
> [ 2041.273976] microsoft 0005:045E:02FD.000C: Event data for report 1 was too
> short (16 vs 15)
> [ 2041.277912] microsoft 0005:045E:02FD.000C: Event data for report 1 was too
> short (16 vs 15)
> [ 2041.280044] microsoft 0005:045E:02FD.000C: Event data for report 1 was too
> short (16 vs 15)
> [ 2041.288927] microsoft 0005:045E:02FD.000C: Event data for report 1 was too
> short (16 vs 15)
> [ 2041.300915] microsoft 0005:045E:02FD.000C: Event data for report 1 was too
> short (16 vs 15)
> [ 2041.309919] microsoft 0005:045E:02FD.000C: Event data for report 1 was too
> short (16 vs 15)

-- 
You may reply to this email to add a comment.

You are receiving this mail because:
You are the assignee for the bug.

^ permalink raw reply

* [bluez/bluez]
From: BluezTestBot @ 2026-05-01 21:07 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1076045
  Home:   https://github.com/bluez/bluez

To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications

^ permalink raw reply

* RE: [BlueZ,v1,1/4] shared/hci: Add BPF filter for registered events
From: bluez.test.bot @ 2026-05-01 15:56 UTC (permalink / raw)
  To: linux-bluetooth, luiz.dentz
In-Reply-To: <20260501143847.724150-1-luiz.dentz@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 4532 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1088547

---Test result---

Test Summary:
CheckPatch                    FAIL      1.94 seconds
GitLint                       PASS      1.17 seconds
BuildEll                      PASS      20.18 seconds
BluezMake                     PASS      654.89 seconds
CheckSmatch                   PASS      350.12 seconds
bluezmakeextell               PASS      182.29 seconds
IncrementalBuild              PASS      707.45 seconds
ScanBuild                     PASS      1006.46 seconds

Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[BlueZ,v1,1/4] shared/hci: Add BPF filter for registered events
WARNING:BAD_SIGN_OFF: Non-standard signature: Assisted-by:
#105: 
Assisted-by: Claude:claude-opus-4.6

ERROR:BAD_SIGN_OFF: Unrecognized email address: 'Claude:claude-opus-4.6'
#105: 
Assisted-by: Claude:claude-opus-4.6

/github/workspace/src/patch/14550825.patch total: 1 errors, 1 warnings, 108 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/patch/14550825.patch has style problems, please review.

NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.


[BlueZ,v1,2/4] shared/hci: Add bt_hci_register_subevent for LE Meta events
WARNING:BAD_SIGN_OFF: Non-standard signature: Assisted-by:
#111: 
Assisted-by: Claude:claude-opus-4.6

ERROR:BAD_SIGN_OFF: Unrecognized email address: 'Claude:claude-opus-4.6'
#111: 
Assisted-by: Claude:claude-opus-4.6

/github/workspace/src/patch/14550827.patch total: 1 errors, 1 warnings, 317 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/patch/14550827.patch has style problems, please review.

NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.


[BlueZ,v1,3/4] ranging/rap_hci: Use bt_hci_register_subevent for LE CS events
WARNING:BAD_SIGN_OFF: Non-standard signature: Assisted-by:
#109: 
Assisted-by: Claude:claude-opus-4.6

ERROR:BAD_SIGN_OFF: Unrecognized email address: 'Claude:claude-opus-4.6'
#109: 
Assisted-by: Claude:claude-opus-4.6

/github/workspace/src/patch/14550828.patch total: 1 errors, 1 warnings, 269 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/patch/14550828.patch has style problems, please review.

NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.


[BlueZ,v1,4/4] hci-tester: Use bt_hci_register_subevent for LE Meta events
WARNING:BAD_SIGN_OFF: Non-standard signature: Assisted-by:
#107: 
Assisted-by: Claude:claude-opus-4.6

ERROR:BAD_SIGN_OFF: Unrecognized email address: 'Claude:claude-opus-4.6'
#107: 
Assisted-by: Claude:claude-opus-4.6

/github/workspace/src/patch/14550826.patch total: 1 errors, 1 warnings, 116 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/patch/14550826.patch has style problems, please review.

NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.




https://github.com/bluez/bluez/pull/2091

---
Regards,
Linux Bluetooth


^ permalink raw reply

* [bluez/bluez]
From: BluezTestBot @ 2026-05-01 15:06 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1088223
  Home:   https://github.com/bluez/bluez

To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications

^ permalink raw reply

* [bluez/bluez]
From: BluezTestBot @ 2026-05-01 15:06 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1088308
  Home:   https://github.com/bluez/bluez

To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications

^ permalink raw reply

* [bluez/bluez] 323d54: shared/hci: Add BPF filter for registered events
From: Luiz Augusto von Dentz @ 2026-05-01 15:06 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1088547
  Home:   https://github.com/bluez/bluez
  Commit: 323d54f958ff446ecd6897c8ce1aade29639e454
      https://github.com/bluez/bluez/commit/323d54f958ff446ecd6897c8ce1aade29639e454
  Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  Date:   2026-05-01 (Fri, 01 May 2026)

  Changed paths:
    M src/shared/hci.c

  Log Message:
  -----------
  shared/hci: Add BPF filter for registered events

Implement a BPF socket filter in bt_hci_register/bt_hci_unregister that
uses setsockopt(SO_ATTACH_FILTER) to only accept HCI events that have
been registered, plus BT_HCI_EVT_CMD_COMPLETE and BT_HCI_EVT_CMD_STATUS
which are always needed for command response processing.

The filter is rebuilt each time an event is registered or unregistered,
and only applies to non-stream (raw socket) connections.

Assisted-by: Claude:claude-opus-4.6


  Commit: 445437b236ab5b3c7b9c888ae1baa52176216928
      https://github.com/bluez/bluez/commit/445437b236ab5b3c7b9c888ae1baa52176216928
  Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  Date:   2026-05-01 (Fri, 01 May 2026)

  Changed paths:
    M src/shared/hci.c
    M src/shared/hci.h

  Log Message:
  -----------
  shared/hci: Add bt_hci_register_subevent for LE Meta events

Add bt_hci_register_subevent/bt_hci_unregister_subevent API that allows
registering for specific LE Meta Event subevents. The BPF filter is
extended to accept BT_HCI_EVT_LE_META_EVENT packets and then check the
subevent byte (offset 4) against registered subevents.

Since bt_hci_register_subevent is only used with BT_HCI_EVT_LE_META_EVENT,
the event parameter is omitted. The subevent list reuses struct evt where
evt->event stores the subevent code.

Assisted-by: Claude:claude-opus-4.6


  Commit: 5b1e05389d250781fbfd1e72308395b297f9414a
      https://github.com/bluez/bluez/commit/5b1e05389d250781fbfd1e72308395b297f9414a
  Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  Date:   2026-05-01 (Fri, 01 May 2026)

  Changed paths:
    M profiles/ranging/rap_hci.c

  Log Message:
  -----------
  ranging/rap_hci: Use bt_hci_register_subevent for LE CS events

Replace the single BT_HCI_EVT_LE_META_EVENT registration and subevent
dispatch table with individual bt_hci_register_subevent calls for each
CS subevent. This enables BPF filtering at the socket level for each
specific subevent and removes the manual subevent dispatch logic.

Event IDs are stored in a struct queue for flexible management.

Assisted-by: Claude:claude-opus-4.6


  Commit: dfbc31a733555c70ff0c6e74ba1834908485a950
      https://github.com/bluez/bluez/commit/dfbc31a733555c70ff0c6e74ba1834908485a950
  Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  Date:   2026-05-01 (Fri, 01 May 2026)

  Changed paths:
    M tools/hci-tester.c

  Log Message:
  -----------
  hci-tester: Use bt_hci_register_subevent for LE Meta events

Convert all bt_hci_register(BT_HCI_EVT_LE_META_EVENT) calls to use
bt_hci_register_subevent with the specific subevent code. Update
callbacks to work with data that no longer contains the subevent byte
prefix, since bt_hci_register_subevent strips it before dispatch.

Assisted-by: Claude:claude-opus-4.6


Compare: https://github.com/bluez/bluez/compare/323d54f958ff%5E...dfbc31a73355

To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications

^ permalink raw reply

* [PATCH BlueZ v1 3/4] ranging/rap_hci: Use bt_hci_register_subevent for LE CS events
From: Luiz Augusto von Dentz @ 2026-05-01 14:38 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260501143847.724150-1-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Replace the single BT_HCI_EVT_LE_META_EVENT registration and subevent
dispatch table with individual bt_hci_register_subevent calls for each
CS subevent. This enables BPF filtering at the socket level for each
specific subevent and removes the manual subevent dispatch logic.

Event IDs are stored in a struct queue for flexible management.

Assisted-by: Claude:claude-opus-4.6
---
 profiles/ranging/rap_hci.c | 193 ++++++++++++++-----------------------
 1 file changed, 71 insertions(+), 122 deletions(-)

diff --git a/profiles/ranging/rap_hci.c b/profiles/ranging/rap_hci.c
index 08ddc077ce94..8e65e5ef87bd 100644
--- a/profiles/ranging/rap_hci.c
+++ b/profiles/ranging/rap_hci.c
@@ -61,7 +61,7 @@ struct cs_state_machine {
 	enum cs_state old_state;
 	struct bt_hci *hci;
 	struct bt_rap *rap;
-	unsigned int event_id;
+	struct queue *event_ids;
 	bool initiator;
 	bool procedure_active;
 	struct bt_rap_hci_cs_options cs_opt;  /* Per-instance CS options */
@@ -302,7 +302,7 @@ static void rap_send_hci_def_settings_command(struct cs_state_machine *sm,
 		error("Failed to send default settings cmd");
 }
 
-static void rap_rd_rmt_supp_cap_cmplt_evt(const uint8_t *data, uint8_t size,
+static void rap_rd_rmt_supp_cap_cmplt_evt(const void *data, uint8_t size,
 					   void *user_data)
 {
 	struct cs_state_machine *sm = user_data;
@@ -348,7 +348,7 @@ static void rap_rd_rmt_supp_cap_cmplt_evt(const uint8_t *data, uint8_t size,
 	cs_set_state(sm, CS_STATE_INIT);
 }
 
-static void rap_cs_config_cmplt_evt(const uint8_t *data, uint8_t size,
+static void rap_cs_config_cmplt_evt(const void *data, uint8_t size,
 				    void *user_data)
 {
 	struct cs_state_machine *sm = user_data;
@@ -439,7 +439,7 @@ static void rap_cs_config_cmplt_evt(const uint8_t *data, uint8_t size,
 	bt_rap_hci_cs_config_complete_callback(size, &rap_ev, sm->rap);
 }
 
-static void rap_cs_sec_enable_cmplt_evt(const uint8_t *data, uint8_t size,
+static void rap_cs_sec_enable_cmplt_evt(const void *data, uint8_t size,
 					 void *user_data)
 {
 	struct cs_state_machine *sm = user_data;
@@ -500,7 +500,7 @@ static void rap_cs_sec_enable_cmplt_evt(const uint8_t *data, uint8_t size,
 	bt_rap_hci_cs_sec_enable_complete_callback(size, &rap_ev, sm->rap);
 }
 
-static void rap_cs_proc_enable_cmplt_evt(const uint8_t *data, uint8_t size,
+static void rap_cs_proc_enable_cmplt_evt(const void *data, uint8_t size,
 					  void *user_data)
 {
 	struct cs_state_machine *sm = user_data;
@@ -800,7 +800,7 @@ static void parse_cs_step(struct iovec *iov, struct cs_step_data *step,
 	}
 }
 
-static void rap_cs_subevt_result_evt(const uint8_t *data, uint8_t size,
+static void rap_cs_subevt_result_evt(const void *data, uint8_t size,
 				void *user_data)
 {
 	struct cs_state_machine *sm = (struct cs_state_machine *) user_data;
@@ -910,7 +910,7 @@ send_event:
 	free(rap_ev);
 }
 
-static void rap_cs_subevt_result_cont_evt(const uint8_t *data, uint8_t size,
+static void rap_cs_subevt_result_cont_evt(const void *data, uint8_t size,
 					void *user_data)
 {
 	struct cs_state_machine *sm = (struct cs_state_machine *) user_data;
@@ -1009,113 +1009,12 @@ send_event:
 }
 
 /* Subevent handler function type */
-typedef void (*subevent_handler_t)(const uint8_t *data, uint8_t size,
-				   void *user_data);
 
-/* Subevent table entry */
-struct subevent_entry {
-	uint8_t opcode;
-	uint8_t min_len;
-	uint8_t max_len;
-	subevent_handler_t handler;
-	const char *name;
-};
-
-/* Macro to define HCI event entries
- * Note: min_len excludes the subevent byte since it's stripped before dispatch
- */
-#define HCI_EVT(_opcode, _struct, _handler, _name) \
-	{ \
-		.opcode = _opcode, \
-		.min_len = sizeof(_struct), \
-		.max_len = 0xFF, \
-		.handler = _handler, \
-		.name = _name \
-	}
-
-/* Subevent dispatch table */
-static const struct subevent_entry subevent_table[] = {
-	HCI_EVT(BT_HCI_EVT_LE_CS_RD_REM_SUPP_CAP_COMPLETE,
-		struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete,
-		rap_rd_rmt_supp_cap_cmplt_evt,
-		"CS Read Remote Supported Capabilities Complete"),
-	HCI_EVT(BT_HCI_EVT_LE_CS_CONFIG_COMPLETE,
-		struct bt_hci_evt_le_cs_config_complete,
-		rap_cs_config_cmplt_evt,
-		"CS Config Complete"),
-	HCI_EVT(BT_HCI_EVT_LE_CS_SEC_ENABLE_COMPLETE,
-		struct bt_hci_evt_le_cs_sec_enable_complete,
-		rap_cs_sec_enable_cmplt_evt,
-		"CS Security Enable Complete"),
-	HCI_EVT(BT_HCI_EVT_LE_CS_PROC_ENABLE_COMPLETE,
-		struct bt_hci_evt_le_cs_proc_enable_complete,
-		rap_cs_proc_enable_cmplt_evt,
-		"CS Procedure Enable Complete"),
-	HCI_EVT(BT_HCI_EVT_LE_CS_SUBEVENT_RESULT,
-		struct bt_hci_evt_le_cs_subevent_result,
-		rap_cs_subevt_result_evt,
-		"CS Subevent Result"),
-	HCI_EVT(BT_HCI_EVT_LE_CS_SUBEVENT_RESULT_CONTINUE,
-		struct bt_hci_evt_le_cs_subevent_result_continue,
-		rap_cs_subevt_result_cont_evt,
-		"CS Subevent Result Continue")
-};
-
-#undef HCI_EVT
-
-#define SUBEVENT_TABLE_SIZE ARRAY_SIZE(subevent_table)
-
-/* HCI Event Registration */
-static void rap_handle_hci_events(const void *data, uint8_t size,
-				void *user_data)
+static void unregister_event_id(void *data, void *user_data)
 {
-	struct iovec iov;
-	uint8_t subevent;
-	const struct subevent_entry *entry = NULL;
-	size_t i;
+	struct bt_hci *hci = user_data;
 
-	/* Initialize iovec with the event data */
-	iov.iov_base = (void *) data;
-	iov.iov_len = size;
-
-	/* Pull the subevent code */
-	if (!util_iov_pull_u8(&iov, &subevent)) {
-		DBG("Failed to parse subevent code");
-		return;
-	}
-
-	/* Find the subevent in the table */
-	for (i = 0; i < SUBEVENT_TABLE_SIZE; i++) {
-		if (subevent_table[i].opcode == subevent) {
-			entry = &subevent_table[i];
-			break;
-		}
-	}
-
-	/* Check if subevent is supported */
-	if (!entry) {
-		DBG("Unknown subevent: 0x%02X", subevent);
-		return;
-	}
-
-	/* Validate payload length */
-	if (iov.iov_len < entry->min_len) {
-		DBG("%s: payload too short (%zu < %u)",
-		    entry->name, iov.iov_len, entry->min_len);
-		return;
-	}
-
-	if (entry->max_len != 0xFF && iov.iov_len > entry->max_len) {
-		DBG("%s: payload too long (%zu > %u)",
-		    entry->name, iov.iov_len, entry->max_len);
-		return;
-	}
-
-	/* Call the handler */
-	DBG("Handling %s (opcode=0x%02X, len=%zu)",
-	    entry->name, subevent, iov.iov_len);
-
-	entry->handler(iov.iov_base, iov.iov_len, user_data);
+	bt_hci_unregister_subevent(hci, PTR_TO_UINT(data));
 }
 
 void *bt_rap_attach_hci(struct bt_rap *rap, struct bt_hci *hci,
@@ -1123,6 +1022,7 @@ void *bt_rap_attach_hci(struct bt_rap *rap, struct bt_hci *hci,
 			int8_t max_tx_power)
 {
 	struct cs_state_machine *sm;
+	unsigned int id;
 
 	if (!rap || !hci) {
 		error("rap or hci null");
@@ -1140,22 +1040,68 @@ void *bt_rap_attach_hci(struct bt_rap *rap, struct bt_hci *hci,
 	cs_state_machine_init(sm, rap, hci, role, cs_sync_ant_sel,
 				max_tx_power);
 
-	sm->event_id = bt_hci_register(hci, BT_HCI_EVT_LE_META_EVENT,
-					rap_handle_hci_events, sm, NULL);
+	sm->event_ids = queue_new();
 
-	DBG("bt_hci_register done, event_id : %d", sm->event_id);
+	/* Register each LE Meta subevent individually */
+	id = bt_hci_register_subevent(hci,
+			BT_HCI_EVT_LE_CS_RD_REM_SUPP_CAP_COMPLETE,
+			rap_rd_rmt_supp_cap_cmplt_evt, sm, NULL);
+	if (!id)
+		goto fail;
 
-	if (!sm->event_id) {
-		error("Failed to register hci le meta events");
-		error("event_id=0x%02X", sm->event_id);
-		free(sm);
-		return NULL;
-	}
+	queue_push_tail(sm->event_ids, UINT_TO_PTR(id));
+
+	id = bt_hci_register_subevent(hci,
+			BT_HCI_EVT_LE_CS_CONFIG_COMPLETE,
+			rap_cs_config_cmplt_evt, sm, NULL);
+	if (!id)
+		goto fail;
+
+	queue_push_tail(sm->event_ids, UINT_TO_PTR(id));
+
+	id = bt_hci_register_subevent(hci,
+			BT_HCI_EVT_LE_CS_SEC_ENABLE_COMPLETE,
+			rap_cs_sec_enable_cmplt_evt, sm, NULL);
+	if (!id)
+		goto fail;
+
+	queue_push_tail(sm->event_ids, UINT_TO_PTR(id));
+
+	id = bt_hci_register_subevent(hci,
+			BT_HCI_EVT_LE_CS_PROC_ENABLE_COMPLETE,
+			rap_cs_proc_enable_cmplt_evt, sm, NULL);
+	if (!id)
+		goto fail;
+
+	queue_push_tail(sm->event_ids, UINT_TO_PTR(id));
+
+	id = bt_hci_register_subevent(hci,
+			BT_HCI_EVT_LE_CS_SUBEVENT_RESULT,
+			rap_cs_subevt_result_evt, sm, NULL);
+	if (!id)
+		goto fail;
+
+	queue_push_tail(sm->event_ids, UINT_TO_PTR(id));
+
+	id = bt_hci_register_subevent(hci,
+			BT_HCI_EVT_LE_CS_SUBEVENT_RESULT_CONTINUE,
+			rap_cs_subevt_result_cont_evt, sm, NULL);
+	if (!id)
+		goto fail;
+
+	queue_push_tail(sm->event_ids, UINT_TO_PTR(id));
 
 	DBG("CS options: role=%u, cs_sync_ant_sel=%u, max_tx_power=%d",
 		role, cs_sync_ant_sel, max_tx_power);
 
 	return sm;
+
+fail:
+	error("Failed to register hci le meta subevents");
+	queue_foreach(sm->event_ids, unregister_event_id, hci);
+	queue_destroy(sm->event_ids, NULL);
+	free(sm);
+	return NULL;
 }
 
 bool bt_rap_set_conn_handle(void *hci_sm, struct bt_rap *rap, uint16_t handle,
@@ -1204,8 +1150,11 @@ void bt_rap_detach_hci(struct bt_rap *rap, void *hci_sm)
 	/* Cleanup the per-instance state machine */
 	if (sm) {
 		/* Unregister HCI events */
-		if (sm->event_id && sm->hci)
-			bt_hci_unregister(sm->hci, sm->event_id);
+		if (sm->hci)
+			queue_foreach(sm->event_ids, unregister_event_id,
+								sm->hci);
+
+		queue_destroy(sm->event_ids, NULL);
 
 		/* Clean up per-instance connection mappings */
 		remove_rap_mappings(sm);
-- 
2.53.0


^ permalink raw reply related

* [PATCH BlueZ v1 2/4] shared/hci: Add bt_hci_register_subevent for LE Meta events
From: Luiz Augusto von Dentz @ 2026-05-01 14:38 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260501143847.724150-1-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Add bt_hci_register_subevent/bt_hci_unregister_subevent API that allows
registering for specific LE Meta Event subevents. The BPF filter is
extended to accept BT_HCI_EVT_LE_META_EVENT packets and then check the
subevent byte (offset 4) against registered subevents.

Since bt_hci_register_subevent is only used with BT_HCI_EVT_LE_META_EVENT,
the event parameter is omitted. The subevent list reuses struct evt where
evt->event stores the subevent code.

Assisted-by: Claude:claude-opus-4.6
---
 src/shared/hci.c | 240 ++++++++++++++++++++++++++++++++++++++++-------
 src/shared/hci.h |   6 ++
 2 files changed, 212 insertions(+), 34 deletions(-)

diff --git a/src/shared/hci.c b/src/shared/hci.c
index 5105b0b2f320..40326fc810e6 100644
--- a/src/shared/hci.c
+++ b/src/shared/hci.c
@@ -45,6 +45,7 @@ struct bt_hci {
 	struct queue *cmd_queue;
 	struct queue *rsp_queue;
 	struct queue *evt_list;
+	struct queue *subevt_list;
 	struct queue *data_queue;
 };
 
@@ -239,6 +240,21 @@ static void process_notify(void *data, void *user_data)
 						hdr->plen, evt->user_data);
 }
 
+struct subevt_data {
+	uint8_t subevent;
+	const void *data;
+	uint8_t size;
+};
+
+static void process_subevt_notify(void *data, void *user_data)
+{
+	struct subevt_data *sd = user_data;
+	struct evt *evt = data;
+
+	if (evt->event == sd->subevent)
+		evt->callback(sd->data, sd->size, evt->user_data);
+}
+
 static void process_event(struct bt_hci *hci, const void *data, size_t size)
 {
 	const struct bt_hci_evt_hdr *hdr = data;
@@ -275,6 +291,16 @@ static void process_event(struct bt_hci *hci, const void *data, size_t size)
 
 	default:
 		queue_foreach(hci->evt_list, process_notify, (void *) hdr);
+		if (hdr->evt == BT_HCI_EVT_LE_META_EVENT && size > 0) {
+			const uint8_t *params = data;
+			struct subevt_data sd;
+
+			sd.subevent = params[0];
+			sd.data = data + 1;
+			sd.size = size - 1;
+			queue_foreach(hci->subevt_list,
+					process_subevt_notify, &sd);
+		}
 		break;
 	}
 }
@@ -332,10 +358,12 @@ static struct bt_hci *create_hci(int fd)
 	hci->cmd_queue = queue_new();
 	hci->rsp_queue = queue_new();
 	hci->evt_list = queue_new();
+	hci->subevt_list = queue_new();
 	hci->data_queue = queue_new();
 
 	if (!io_set_read_handler(hci->io, io_read_callback, hci, NULL)) {
 		queue_destroy(hci->evt_list, NULL);
+		queue_destroy(hci->subevt_list, NULL);
 		queue_destroy(hci->rsp_queue, NULL);
 		queue_destroy(hci->cmd_queue, NULL);
 		queue_destroy(hci->data_queue, NULL);
@@ -458,6 +486,7 @@ void bt_hci_unref(struct bt_hci *hci)
 		return;
 
 	queue_destroy(hci->evt_list, evt_free);
+	queue_destroy(hci->subevt_list, evt_free);
 	queue_destroy(hci->cmd_queue, cmd_free);
 	queue_destroy(hci->rsp_queue, cmd_free);
 	queue_destroy(hci->data_queue, data_free);
@@ -571,7 +600,7 @@ static void update_evt_filter(struct bt_hci *hci)
 	const struct queue_entry *entry;
 	struct sock_filter *filters;
 	struct sock_fprog fprog;
-	unsigned int count, i;
+	unsigned int evt_count, subevt_count, count, i;
 	int fd;
 
 	fd = io_get_fd(hci->io);
@@ -582,21 +611,38 @@ static void update_evt_filter(struct bt_hci *hci)
 	if (hci->is_stream)
 		return;
 
-	count = queue_length(hci->evt_list);
+	evt_count = queue_length(hci->evt_list);
+	subevt_count = queue_length(hci->subevt_list);
 
-	/* Build filter: load event code, check defaults + registered events.
-	 * Packet layout for HCI_CHANNEL_RAW: [H4 type (1 byte)][evt code (1)]
-	 * So event code is at offset 1.
+	/* Filter structure:
+	 * Packet layout: [H4 type(1)][evt code(1)][plen(1)][params...]
+	 * For LE Meta: params[0] is the subevent code (offset 3 from start)
 	 *
-	 * Filter structure:
 	 *   [0] Load byte at offset 1 (event code)
-	 *   [1] JEQ BT_HCI_EVT_CMD_COMPLETE -> accept
-	 *   [2] JEQ BT_HCI_EVT_CMD_STATUS -> accept
-	 *   [3..3+count-1] JEQ registered_event -> accept
-	 *   [3+count] reject
-	 *   [4+count] accept
+	 *   [1] JEQ CMD_COMPLETE -> accept
+	 *   [2] JEQ CMD_STATUS -> accept
+	 *   [3] JEQ LE_META -> subevent_check (if subevts registered)
+	 *   [4..4+evt_count-1] JEQ registered_event -> accept
+	 *   [4+evt_count] reject
+	 *   -- subevent section (if subevt_count > 0) --
+	 *   [5+evt_count] Load byte at offset 3 (subevent code)
+	 *   [6+evt_count..6+evt_count+subevt_count-1] JEQ subevent -> accept
+	 *   [6+evt_count+subevt_count] reject
+	 *   -- shared accept --
+	 *   [last] accept
 	 */
-	filters = malloc(sizeof(*filters) * (count + 5));
+
+	/* Without subevents: 3 (defaults) + evt_count + reject + accept =
+	 *                    evt_count + 5
+	 * With subevents: 4 (defaults+LE_META) + evt_count + reject +
+	 *                 1 (load subevent) + subevt_count + reject + accept
+	 */
+	if (subevt_count)
+		count = 4 + evt_count + 1 + 1 + subevt_count + 1 + 1;
+	else
+		count = 3 + evt_count + 1 + 1;
+
+	filters = malloc(sizeof(*filters) * count);
 	if (!filters)
 		return;
 
@@ -606,32 +652,106 @@ static void update_evt_filter(struct bt_hci *hci)
 	filters[i++] = (struct sock_filter)
 		BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 1);
 
-	/* Check BT_HCI_EVT_CMD_COMPLETE (0x0e) */
-	filters[i++] = (struct sock_filter)
-		BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BT_HCI_EVT_CMD_COMPLETE,
-			 count + 2, 0);
-
-	/* Check BT_HCI_EVT_CMD_STATUS (0x0f) */
-	filters[i++] = (struct sock_filter)
-		BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BT_HCI_EVT_CMD_STATUS,
-			 count + 1, 0);
-
-	/* Check each registered event */
-	entry = queue_get_entries(hci->evt_list);
-	while (entry) {
-		const struct evt *evt = entry->data;
-		unsigned int jump = count - (i - 3);
+	if (subevt_count) {
+		/* accept is at index: count - 1
+		 * From instruction at index i, jump_true = (count-1) - (i+1)
+		 */
 
+		/* Check BT_HCI_EVT_CMD_COMPLETE -> accept */
 		filters[i] = (struct sock_filter)
-			BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, evt->event,
-				 jump, 0);
+			BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K,
+				 BT_HCI_EVT_CMD_COMPLETE,
+				 count - 1 - (i + 1), 0);
 		i++;
-		entry = entry->next;
-	}
 
-	/* Reject */
-	filters[i++] = (struct sock_filter)
-		BPF_STMT(BPF_RET | BPF_K, 0);
+		/* Check BT_HCI_EVT_CMD_STATUS -> accept */
+		filters[i] = (struct sock_filter)
+			BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K,
+				 BT_HCI_EVT_CMD_STATUS,
+				 count - 1 - (i + 1), 0);
+		i++;
+
+		/* Check LE_META -> subevent section
+		 * subevent section starts at: 4 + evt_count + 1
+		 * (after the evt reject instruction)
+		 */
+		filters[i] = (struct sock_filter)
+			BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K,
+				 BT_HCI_EVT_LE_META_EVENT,
+				 4 + evt_count + 1 - (i + 1), 0);
+		i++;
+
+		/* Check each registered event -> accept */
+		entry = queue_get_entries(hci->evt_list);
+		while (entry) {
+			const struct evt *evt = entry->data;
+
+			filters[i] = (struct sock_filter)
+				BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K,
+					 evt->event,
+					 count - 1 - (i + 1), 0);
+			i++;
+			entry = entry->next;
+		}
+
+		/* Reject (for non-matching events) */
+		filters[i++] = (struct sock_filter)
+			BPF_STMT(BPF_RET | BPF_K, 0);
+
+		/* Subevent section: load subevent byte at offset 3 */
+		filters[i++] = (struct sock_filter)
+			BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 3);
+
+		/* Check each registered subevent -> accept */
+		entry = queue_get_entries(hci->subevt_list);
+		while (entry) {
+			const struct evt *evt = entry->data;
+
+			filters[i] = (struct sock_filter)
+				BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K,
+					 evt->event,
+					 count - 1 - (i + 1), 0);
+			i++;
+			entry = entry->next;
+		}
+
+		/* Reject (for non-matching subevents) */
+		filters[i++] = (struct sock_filter)
+			BPF_STMT(BPF_RET | BPF_K, 0);
+	} else {
+		/* No subevents - simple filter */
+
+		/* Check BT_HCI_EVT_CMD_COMPLETE -> accept */
+		filters[i] = (struct sock_filter)
+			BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K,
+				 BT_HCI_EVT_CMD_COMPLETE,
+				 count - 1 - (i + 1), 0);
+		i++;
+
+		/* Check BT_HCI_EVT_CMD_STATUS -> accept */
+		filters[i] = (struct sock_filter)
+			BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K,
+				 BT_HCI_EVT_CMD_STATUS,
+				 count - 1 - (i + 1), 0);
+		i++;
+
+		/* Check each registered event -> accept */
+		entry = queue_get_entries(hci->evt_list);
+		while (entry) {
+			const struct evt *evt = entry->data;
+
+			filters[i] = (struct sock_filter)
+				BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K,
+					 evt->event,
+					 count - 1 - (i + 1), 0);
+			i++;
+			entry = entry->next;
+		}
+
+		/* Reject */
+		filters[i++] = (struct sock_filter)
+			BPF_STMT(BPF_RET | BPF_K, 0);
+	}
 
 	/* Accept */
 	filters[i++] = (struct sock_filter)
@@ -744,6 +864,58 @@ bool bt_hci_unregister(struct bt_hci *hci, unsigned int id)
 	return true;
 }
 
+
+unsigned int bt_hci_register_subevent(struct bt_hci *hci,
+				uint8_t subevent,
+				bt_hci_callback_func_t callback,
+				void *user_data, bt_hci_destroy_func_t destroy)
+{
+	struct evt *evt;
+
+	if (!hci)
+		return 0;
+
+	evt = new0(struct evt, 1);
+	evt->event = subevent;
+
+	if (hci->next_evt_id < 1)
+		hci->next_evt_id = 1;
+
+	evt->id = hci->next_evt_id++;
+
+	evt->callback = callback;
+	evt->destroy = destroy;
+	evt->user_data = user_data;
+
+	if (!queue_push_tail(hci->subevt_list, evt)) {
+		free(evt);
+		return 0;
+	}
+
+	update_evt_filter(hci);
+
+	return evt->id;
+}
+
+bool bt_hci_unregister_subevent(struct bt_hci *hci, unsigned int id)
+{
+	struct evt *evt;
+
+	if (!hci || !id)
+		return false;
+
+	evt = queue_remove_if(hci->subevt_list, match_evt_id,
+							UINT_TO_PTR(id));
+	if (!evt)
+		return false;
+
+	evt_free(evt);
+
+	update_evt_filter(hci);
+
+	return true;
+}
+
 bool bt_hci_get_conn_handle(struct bt_hci *hci, const uint8_t *bdaddr,
 				uint16_t *handle)
 {
diff --git a/src/shared/hci.h b/src/shared/hci.h
index 800dc4946b97..5be48577f9db 100644
--- a/src/shared/hci.h
+++ b/src/shared/hci.h
@@ -42,5 +42,11 @@ unsigned int bt_hci_register(struct bt_hci *hci, uint8_t event,
 				void *user_data, bt_hci_destroy_func_t destroy);
 bool bt_hci_unregister(struct bt_hci *hci, unsigned int id);
 
+unsigned int bt_hci_register_subevent(struct bt_hci *hci,
+				uint8_t subevent,
+				bt_hci_callback_func_t callback,
+				void *user_data, bt_hci_destroy_func_t destroy);
+bool bt_hci_unregister_subevent(struct bt_hci *hci, unsigned int id);
+
 bool bt_hci_get_conn_handle(struct bt_hci *hci, const uint8_t *bdaddr,
 				uint16_t *handle);
-- 
2.53.0


^ permalink raw reply related

* [PATCH BlueZ v1 4/4] hci-tester: Use bt_hci_register_subevent for LE Meta events
From: Luiz Augusto von Dentz @ 2026-05-01 14:38 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260501143847.724150-1-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Convert all bt_hci_register(BT_HCI_EVT_LE_META_EVENT) calls to use
bt_hci_register_subevent with the specific subevent code. Update
callbacks to work with data that no longer contains the subevent byte
prefix, since bt_hci_register_subevent strips it before dispatch.

Assisted-by: Claude:claude-opus-4.6
---
 tools/hci-tester.c | 59 +++++++++++++---------------------------------
 1 file changed, 17 insertions(+), 42 deletions(-)

diff --git a/tools/hci-tester.c b/tools/hci-tester.c
index 79193220feec..b8446ee83ccf 100644
--- a/tools/hci-tester.c
+++ b/tools/hci-tester.c
@@ -407,17 +407,9 @@ static void test_le_rand(const void *test_data)
 static void test_le_read_local_pk_complete(const void *data, uint8_t size,
 								void *user_data)
 {
-	const uint8_t *event = data;
-	const struct bt_hci_evt_le_read_local_pk256_complete *evt;
+	const struct bt_hci_evt_le_read_local_pk256_complete *evt = data;
 	struct le_keys *keys = user_data;
 
-	if (*event != BT_HCI_EVT_LE_READ_LOCAL_PK256_COMPLETE) {
-		tester_warn("Failed Read Local PK256 command");
-		tester_test_failed();
-		return;
-	}
-
-	evt = (void *)(event + 1);
 	if (evt->status) {
 		tester_warn("HCI Read Local PK complete failed (0x%02x)",
 								evt->status);
@@ -450,7 +442,8 @@ static void test_le_read_local_pk(const void *test_data)
 	struct bt_hci_cmd_set_event_mask sem;
 	struct bt_hci_cmd_le_set_event_mask lsem;
 
-	bt_hci_register(user->hci_ut, BT_HCI_EVT_LE_META_EVENT,
+	bt_hci_register_subevent(user->hci_ut,
+				BT_HCI_EVT_LE_READ_LOCAL_PK256_COMPLETE,
 				test_le_read_local_pk_complete,
 				(void *)test_data, NULL);
 
@@ -480,17 +473,9 @@ static void test_le_read_local_pk(const void *test_data)
 static void setup_le_read_local_pk_complete(const void *data, uint8_t size,
 								void *user_data)
 {
-	const uint8_t *event = data;
-	const struct bt_hci_evt_le_read_local_pk256_complete *evt;
+	const struct bt_hci_evt_le_read_local_pk256_complete *evt = data;
 	struct le_keys *keys = user_data;
 
-	if (*event != BT_HCI_EVT_LE_READ_LOCAL_PK256_COMPLETE) {
-		tester_warn("Failed Read Local PK256 command");
-		tester_setup_failed();
-		return;
-	}
-
-	evt = (void *)(event + 1);
 	if (evt->status) {
 		tester_warn("HCI Read Local PK complete failed (0x%02x)",
 								evt->status);
@@ -523,7 +508,8 @@ static void setup_le_generate_dhkey(const void *test_data)
 	struct bt_hci_cmd_set_event_mask sem;
 	struct bt_hci_cmd_le_set_event_mask lsem;
 
-	bt_hci_register(user->hci_ut, BT_HCI_EVT_LE_META_EVENT,
+	bt_hci_register_subevent(user->hci_ut,
+				BT_HCI_EVT_LE_READ_LOCAL_PK256_COMPLETE,
 				setup_le_read_local_pk_complete,
 				(void *)test_data, NULL);
 
@@ -554,18 +540,10 @@ static void setup_le_generate_dhkey(const void *test_data)
 static void test_le_generate_dhkey_complete(const void *data, uint8_t size,
 								void *user_data)
 {
-	const uint8_t *event = data;
-	const struct bt_hci_evt_le_generate_dhkey_complete *evt;
+	const struct bt_hci_evt_le_generate_dhkey_complete *evt = data;
 	struct le_keys *keys = user_data;
 	uint8_t dhkey[32];
 
-	if (*event != BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE) {
-		tester_warn("Failed DHKey generation command");
-		tester_test_failed();
-		return;
-	}
-
-	evt = (void *)(event + 1);
 	if (evt->status) {
 		tester_warn("HCI Generate DHKey complete failed (0x%02x)",
 								evt->status);
@@ -613,10 +591,11 @@ static void test_le_generate_dhkey(const void *test_data)
 
 	ecc_make_key(cmd.remote_pk256, keys->remote_sk);
 
-	/* Unregister handler for META event */
-	bt_hci_unregister(user->hci_ut, 1);
+	/* Unregister handler for PK256 subevent */
+	bt_hci_unregister_subevent(user->hci_ut, 1);
 
-	bt_hci_register(user->hci_ut, BT_HCI_EVT_LE_META_EVENT,
+	bt_hci_register_subevent(user->hci_ut,
+				BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE,
 				test_le_generate_dhkey_complete, keys,
 				NULL);
 
@@ -830,15 +809,10 @@ static void teardown_connection(const void *test_data)
 static void test_adv_report(const void *data, uint8_t size, void *user_data)
 {
 	struct user_data *user = tester_get_data();
-	uint8_t subevent = *((uint8_t *) data);
-	const struct bt_hci_evt_le_adv_report *lar = data + 1;
+	const struct bt_hci_evt_le_adv_report *lar = data;
 
-	switch (subevent) {
-	case BT_HCI_EVT_LE_ADV_REPORT:
-		if (!memcmp(lar->addr, user->bdaddr_ut, 6))
-			tester_setup_complete();
-		break;
-	}
+	if (!memcmp(lar->addr, user->bdaddr_ut, 6))
+		tester_setup_complete();
 }
 
 static void setup_advertising_initiated(const void *test_data)
@@ -850,8 +824,9 @@ static void setup_advertising_initiated(const void *test_data)
 	struct bt_hci_cmd_le_set_adv_parameters lsap;
 	struct bt_hci_cmd_le_set_adv_enable lsae;
 
-	bt_hci_register(user->hci_lt, BT_HCI_EVT_LE_META_EVENT,
-					test_adv_report, NULL, NULL);
+	bt_hci_register_subevent(user->hci_lt,
+				BT_HCI_EVT_LE_ADV_REPORT,
+				test_adv_report, NULL, NULL);
 
 	memset(sem.mask, 0, 8);
 	sem.mask[1] |= 0x20;	/* Command Complete */
-- 
2.53.0


^ permalink raw reply related

* [PATCH BlueZ v1 1/4] shared/hci: Add BPF filter for registered events
From: Luiz Augusto von Dentz @ 2026-05-01 14:38 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Implement a BPF socket filter in bt_hci_register/bt_hci_unregister that
uses setsockopt(SO_ATTACH_FILTER) to only accept HCI events that have
been registered, plus BT_HCI_EVT_CMD_COMPLETE and BT_HCI_EVT_CMD_STATUS
which are always needed for command response processing.

The filter is rebuilt each time an event is registered or unregistered,
and only applies to non-stream (raw socket) connections.

Assisted-by: Claude:claude-opus-4.6
---
 src/shared/hci.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)

diff --git a/src/shared/hci.c b/src/shared/hci.c
index 0faa6dea555d..5105b0b2f320 100644
--- a/src/shared/hci.c
+++ b/src/shared/hci.c
@@ -23,6 +23,7 @@
 #include <sys/ioctl.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <linux/filter.h>
 
 #include "bluetooth/hci.h"
 #include "monitor/bt.h"
@@ -565,6 +566,85 @@ bool bt_hci_flush(struct bt_hci *hci)
 	return true;
 }
 
+static void update_evt_filter(struct bt_hci *hci)
+{
+	const struct queue_entry *entry;
+	struct sock_filter *filters;
+	struct sock_fprog fprog;
+	unsigned int count, i;
+	int fd;
+
+	fd = io_get_fd(hci->io);
+	if (fd < 0)
+		return;
+
+	/* If stream-based (not a raw socket), no BPF filtering needed */
+	if (hci->is_stream)
+		return;
+
+	count = queue_length(hci->evt_list);
+
+	/* Build filter: load event code, check defaults + registered events.
+	 * Packet layout for HCI_CHANNEL_RAW: [H4 type (1 byte)][evt code (1)]
+	 * So event code is at offset 1.
+	 *
+	 * Filter structure:
+	 *   [0] Load byte at offset 1 (event code)
+	 *   [1] JEQ BT_HCI_EVT_CMD_COMPLETE -> accept
+	 *   [2] JEQ BT_HCI_EVT_CMD_STATUS -> accept
+	 *   [3..3+count-1] JEQ registered_event -> accept
+	 *   [3+count] reject
+	 *   [4+count] accept
+	 */
+	filters = malloc(sizeof(*filters) * (count + 5));
+	if (!filters)
+		return;
+
+	i = 0;
+
+	/* Load event code byte */
+	filters[i++] = (struct sock_filter)
+		BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 1);
+
+	/* Check BT_HCI_EVT_CMD_COMPLETE (0x0e) */
+	filters[i++] = (struct sock_filter)
+		BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BT_HCI_EVT_CMD_COMPLETE,
+			 count + 2, 0);
+
+	/* Check BT_HCI_EVT_CMD_STATUS (0x0f) */
+	filters[i++] = (struct sock_filter)
+		BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BT_HCI_EVT_CMD_STATUS,
+			 count + 1, 0);
+
+	/* Check each registered event */
+	entry = queue_get_entries(hci->evt_list);
+	while (entry) {
+		const struct evt *evt = entry->data;
+		unsigned int jump = count - (i - 3);
+
+		filters[i] = (struct sock_filter)
+			BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, evt->event,
+				 jump, 0);
+		i++;
+		entry = entry->next;
+	}
+
+	/* Reject */
+	filters[i++] = (struct sock_filter)
+		BPF_STMT(BPF_RET | BPF_K, 0);
+
+	/* Accept */
+	filters[i++] = (struct sock_filter)
+		BPF_STMT(BPF_RET | BPF_K, 0x0fffffff);
+
+	fprog.len = i;
+	fprog.filter = filters;
+
+	setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
+
+	free(filters);
+}
+
 unsigned int bt_hci_register(struct bt_hci *hci, uint8_t event,
 				bt_hci_callback_func_t callback,
 				void *user_data, bt_hci_destroy_func_t destroy)
@@ -591,6 +671,8 @@ unsigned int bt_hci_register(struct bt_hci *hci, uint8_t event,
 		return 0;
 	}
 
+	update_evt_filter(hci);
+
 	return evt->id;
 }
 
@@ -657,6 +739,8 @@ bool bt_hci_unregister(struct bt_hci *hci, unsigned int id)
 
 	evt_free(evt);
 
+	update_evt_filter(hci);
+
 	return true;
 }
 
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH BlueZ v1 1/2] shared/util: Add decoding support for HIDS 1.1 UUIDs
From: patchwork-bot+bluetooth @ 2026-05-01 14:10 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <20260430195114.608794-1-luiz.dentz@gmail.com>

Hello:

This series was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Thu, 30 Apr 2026 15:51:13 -0400 you wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> This adds support for HIDS 1.1 SCI UUIDs:
> 
> HID SCI Mode(0x2c39)
> HID SCI Information(0x2c3a)
> 
> [...]

Here is the summary with links:
  - [BlueZ,v1,1/2] shared/util: Add decoding support for HIDS 1.1 UUIDs
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=2128e1c73ff0
  - [BlueZ,v1,2/2] monitor: Add decoding support for HIDS 1.1 flags and attributes
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=31e4fb1498f4

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply

* [bluez/bluez] 2128e1: shared/util: Add decoding support for HIDS 1.1 UUIDs
From: Luiz Augusto von Dentz @ 2026-05-01 14:04 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/master
  Home:   https://github.com/bluez/bluez
  Commit: 2128e1c73ff0c0dffc4869b52a8664cac7560455
      https://github.com/bluez/bluez/commit/2128e1c73ff0c0dffc4869b52a8664cac7560455
  Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  Date:   2026-04-30 (Thu, 30 Apr 2026)

  Changed paths:
    M src/shared/util.c

  Log Message:
  -----------
  shared/util: Add decoding support for HIDS 1.1 UUIDs

This adds support for HIDS 1.1 SCI UUIDs:

HID SCI Mode(0x2c39)
HID SCI Information(0x2c3a)


  Commit: 31e4fb1498f47dfbf18b414acbbbeac26dcda366
      https://github.com/bluez/bluez/commit/31e4fb1498f47dfbf18b414acbbbeac26dcda366
  Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  Date:   2026-04-30 (Thu, 30 Apr 2026)

  Changed paths:
    M monitor/att.c
    M src/main.conf

  Log Message:
  -----------
  monitor: Add decoding support for HIDS 1.1 flags and attributes

This adds support for HIDS 1.1 SCI flags and attributes:

> LE-ACL: Handle 2048 flags 0x02 dlen 9
      ATT: Read Response (0x0b) len 4
        Handle: 0x0021 Type: HID Information (0x2a4a)
        Value[4]:
        11 01 00 0f                                      ....
            bcdHID: 0x0111
            bCountryCode: 0x00
            Flags: 0x0f
            RemoteWake (0x01)
            NormallyConnectable (0x02)
            SCI Supported (0x04)
            SCI Low Power Mode Supported (0x08)
< LE-ACL: Handle 2048 flags 0x00 dlen 7
      ATT: Read Request (0x0a) len 2
        Handle: 0x003d Type: HID SCI Information (0x2c3a)
> LE-ACL: Handle 2048 flags 0x02 dlen 19
      ATT: Read Response (0x0b) len 14
        Handle: 0x003d Type: HID SCI Information (0x2c3a)
        Value[14]:
        08 02 0a 00 14 00 0a 00 08 00 08 00 08 00        ..............
            Minimum Supported Connection Interval: 1.000 ms (0x08)
            Number of Supported Subgroups: 2
              Minimum Connection Interval[0]: 1.250 ms (0x000a)
              Maximum Connection Interval[0]: 2.500 ms (0x0014)
              Connection Interval Stride[0]: 1.250 ms (0x000a)
              Minimum Connection Interval[1]: 1.000 ms (0x0008)
              Maximum Connection Interval[1]: 1.000 ms (0x0008)
              Connection Interval Stride[1]: 1.000 ms (0x0008)
< LE-ACL: Handle 2048 flags 0x00 dlen 7
      ATT: Read Request (0x0a) len 2
        Handle: 0x003f Type: HID SCI Mode (0x2c39)
> LE-ACL: Handle 2048 flags 0x02 dlen 6
      ATT: Read Response (0x0b) len 1
        Handle: 0x003f Type: HID SCI Mode (0x2c39)
        Value[1]:
        00                                               .
            Mode: None (0x00)


Compare: https://github.com/bluez/bluez/compare/d01616f0c276...31e4fb1498f4

To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox