This document describes how to patch a linux kernel in order to make a Socket Bluetooth CF card (Rev. G, H) work under linux 2.6. The following hardware is being used:
Software is Debian GNU/Linux 4.0 (testing at the time of this writing), Linux kernel 2.6.17 and BlueZ bluetooth stack.
There are various revisions of this card using different bluetooth chipsets [www.holtmann.org] thus requiring different driver modules:
dtl1_cs
kernel module (part of BlueZ). Those devices aren't addressed
by this patch; if they don't work you have to look for some other solution.serial_cs
kernel module (part of standard linux kernel, it's a
generic driver for serial PC cards equipped with an 8250, 16C550, or similar UART chip) as a low-level driver
and hci_uart
(part of BlueZ) as the actual bluetooth device driver.My card is a Rev. H (its UART is a 16C950, or at least compatible with that) so the information in this section primarily refers to this kind of device. However a Rev. G card should behave (almost) the same, while the Rev. E, F are completely different. If you have information about revisions not mentioned here, please send me an e-mail.
When you plug such a card into your computer and do modprobe serial_cs
(note that on most
linux distributions a userspace daemon does this automatically for you), you see
nothing but an ordinary serial port accessible via /dev/ttyS<n>
.
To be able to use the bluetooth chipset which is connected to that serial line
(of course, this serial link is local to the CF card only) you need to run:
hciattach /dev/ttyS<n> socket
This command will automatically load the hci_uart
kernel module if necessary and associate it
with the selected tty device.
Replace <n>
with the number of your BT card's serial port (examine dmesg
after
plugging in the card). Note that hciattach detaches and runs in background as a daemon.
If this succeeds you can see your bluetooth adapter and view its bluetooth MAC address:
> hcitool dev Devices: hci0 00:02:34:56:AF:FE >
If you see a similar output, you most probably don't need the patch described here.
However, when using a 2.6.x kernel it is very likely that hciattach
doesn't succeed,
instead you get the following error message:
BCSP initialization timed out
I found out that hciattach
needs to set the BT card's UART to a baud rate of 230 400
to be able to talk to the bluetooth chipset. However, in linux 2.6 there is a bug in the core serial driver code
which is also used by serial_cs
that prevents the 16C950 (and several other) UARTs from being
programmed to baud rates larger than 115 200. This is the highest baud rate a "classic" PC
serial port can achieve: its baud rate generator is clocked with 1 843 200 Hz (called the
"baud base") and has a minimal clock divisor of 16, leading to the maximum baud rate:
1 843 200 Hz / 16 = 115 200 baud
All higher baud rates require either a higher baud base or an extended UART which supports baud rate divisors
smaller than 16. The former case, a higher baud base, should be no problem for the serial driver -- it only
means that if your application isn't aware of the non-standard baud base you have to select a different (lower)
baud rate there than you actually want to be used.
However, for our Socket Bluetooth card the latter is the case: the baud base is 1 843 200 Hz,
but the 16C950 supports additional divisor
values between 15 and 4, which are selected by writing appropriate values to the control register TCR
.
For more information refer to a 16C950 datasheet, e.g. [OXCF950 rev B
Datasheet, section 6.10, or SER_OXCB950_DS.pdf,
section 7.10].
By comparing the serial driver in kernel 2.6 with the one from kernel 2.4.29 (which does work!) I noticed
that the code necessary to set the TCR
register appropriately is missing in 2.6.
Having found that, it was quite easy to put together a small patch which enables
the use of the two additional divisors 8 and 4 allowing additional baud rates of 230 400 baud and
460 800 baud to be selected on 16C950-compatible UARTs. This patch could make the Socket card work under
each 2.6 kernel I have tried so far.
Unfortunatly the vanilla kernel from www.kernel.org, as well as Debian's
linux-image-2.6.17-2-686
and presumably many more, still (as of linux 2.6.17) suffer from this bug.
See linux kernel mailing list archives for some insight (the patch was first posted in early 2005 and popped
up occasionally in the meantime).
This is what I do to build a patched Debian linux-image-*.deb
package; if you use another
distribution some details might be different. First, download and extract the kernel source tree
(most of the following commands have to be run as root):
> aptitude install linux-source-2.6.17 > cd /usr/src/ > tar xjf linux-source-2.6.17.tar.bz2
This provides you with the kernel sources under /usr/src/linux-source-2.6.17/
.
Of course you can also un-tar to a different location if you like, only make sure to have around 300-600 MiB
of free disk space there (depending on kernel version and the number of modules you select).
As far as I know this source tree already contains the debian-specific patches (please notify me if that's not true).
To compile a kernel under Debian using make-kpkg
you need (at least) the following packages
(kernel-package
depends on the gcc package so you will get a compiler if you don't have one yet):
> aptitude install kernel-package libncurses5-dev
Now configure the kernel, either
manually (cd linux-source-2.6.17 ; make menuconfig
) or simply by using an existing configuration
for that kernel version. In this example I copy the configuration from the debian binary kernel package (I already
had installed that kernel anyway) for my platform, then compile and install the patched kernel:
> aptitude install linux-image-2.6.17-2-686 # get Debian's default kernel .config file > cd /usr/src/linux-source-2.6.17 > cp -a /boot/config-2.6.17-2-686 .config > patch -p1 </path/to/serial_8250.c_2.6.17.patch > make-kpkg clean # only needed if make-kpkg kernel_image has been run in this source tree before > make-kpkg --initrd --append-to-version -8250patch kernel_image > cd .. > dpkg -i linux-image-2.6.17-8250patch_2.6.17-9_i386.deb
Ensure that your boot loader is configured correctly for booting the new kernel image, and reboot. After
that, hciattach
should do its job without further complaints.
hciattach
on card insert/removalOn kernels 2.6.13 or later, the debian package pcmciautils
is being used to configure which
drivers need to be loaded for a specific PC-card. Note that the files in /etc/pcmcia/
as well as the
cardmgr
daemon aren't
used anymore, they apply to kernels 2.6.12 and older and the pcmcia-cs
debian package.
[this might be debian specific?]
Instead, the "new" approach uses udev
rules thus the udevd
daemon
can also handle pcmcia card inserts/removals, so there is no more need for an additional user space daemon.
To have hciattach
called automatically when inserting the bluetooth card I had to add the
following line to /etc/udev/bluez-pcmcia-support.rules
:
# Socket CF+ Personal Network Card Rev 2.5 SUBSYSTEM=="tty", BUS=="pcmcia", SYSFS{prod_id1}=="Socket", SYSFS{prod_id2}=="CF+ Personal Network Card Rev 2.5", RUN+="bluetooth_serial"
This file already contained a number of similar lines for other serial bluetooth devices, I just copied one and
put in the correct values for prod_id<n>
for my card. Those values can be read from
/sys/bus/pcmcia/devices/*/prod_id*
after plugging in the card.
This setup tells udevd
to run /lib/udev/bluetooth_serial
when a card with the given identification is being inserted or removed.
The bluetooth_serial
script then starts or stops hciattach, respectively. It also makes sure that the
correct /dev/ttyS<n>
is being used by hciattach
(the BT card might well get a different device number on each insertion).
In Debian 4.0 (Etch), /etc/udev/bluez-pcmcia-support.rules
and /lib/udev/bluetooth_serial
are both contained in the package bluez-pcmcia-support
.
Hint: to debug udev
configuration changes, udevcontrol log_priority=debug
might
be rather helpful: it makes udevd
be more verbose (see syslog). Don't forget to restart
udevd
or send it a SIGHUP
after altering its configuration or rule files
(in Debian this can be done with invoke-rc.d udev restart
).
At least on my system, the serial driver crashes when I do a suspend-to-disk or suspend-to-ram while the serial
device is in use by an application (no matter if it's hciattach
or, e.g. minicom
). The
same happens with the stock debian kernel so the baud rate patch doesn't cause this behaviour. However I didn't dig into
this issue any further, instead I just unload ("eject") the pcmcia driver before suspending and reload it
after resuming:
pccardctl eject 1 echo shutdown > /sys/power/disk echo disk > /sys/power/state pccardctl insert 1
On an X21 socket 1 is the CF slot, and socket 0 is the PC card slot. If you don't know which slot your BT card
is plugged in, you could also omit the socket number in the pccardctl
call to unload/reload the
drivers of each pcmcia card - this should rarely be a problem.