2011年4月11日 星期一

如何在Android平台上移植藍牙

上星期四上課後就計畫移植Bluetooth USB Dongle到開發版上,利用這個假日整理一下移植藍牙的實作讓同學參考一下,下面是整個移植的過程說明。

環境:
OS:Ubuntu 10.10
DMA-6410XP及DMA-6410L
Bluetooth USB Dongle
Kernel:linux-2.6.29
Android 2.1
編輯Kernel及Android原始碼部分本文不進行詳細敘述,細節請參照開發版所附書籍。
(本文使用的是隨手取得的無牌的香菇造型藍牙傳輸器價格大約在NT$200左右,
應該是Bluetooth V2.0+EDR規格其他並沒有測試過!!建議不要使用太新以避免Kernel內附驅動不支援)



步驟一,Kernel選擇藍牙驅動
在Kernel目錄下執行 make menuconfig
Networking support --->
將 Bluetooth subsystem support 項打星號 " * "
將 RF switch subsystem support 項打星號 " * "


選擇 Bluetooth subsystem support --->
將全部選項打星號 " * "


然後選擇 :
Bluetooth device drivers --->
將下列選項打星號 " * "
HCI USB driver
HCI UART driver
UART (H4) protocol support
HCILL protocol support


退回到Networking support
選擇 RF switch subsystem support --->
將裡面兩項目都打星號 " * "


退出並存檔後接著開始編輯hci_core.h及hci_core.c

步驟二,編輯hci_core.h及hci_core.c
1.編輯hci_core.h
include/net/bluetooth/hci_core.h
在138行找到:
struct device dev;
struct module *owner;
中間插入:
struct rfkill *rfkill;

存檔完成hci_core.h檔案編輯。

2.編輯hci_core.c
net/bluetooth/hci_core.c
在41行找到:
#include <linux/notifier.h>
#include <net/sock.h>
中間插入:
#include <linux/rfkill.h>


在478行找到:
hci_req_lock(hdev);

if (test_bit(HCI_UP, &hdev->flags)) {
......
中間插入:
if (hdev->rfkill && hdev->rfkill->state == RFKILL_STATE_HARD_BLOCKED) {
ret = -EBUSY;
goto done;
}


在820行找到:
/* ---- Interface to HCI drivers ---- */

/* Alloc HCI device */
中間插入:
static int hci_rfkill_set_block(void *data, enum rfkill_state state)
{
struct hci_dev *hdev = data;
bool blocked = !(state == RFKILL_STATE_UNBLOCKED);

BT_DBG("%p name %s blocked %d", hdev, hdev->name, blocked);

if (!blocked)
return 0;

hci_dev_do_close(hdev);

return 0;
}


在923行找到:
hci_register_sysfs(hdev);

hci_notify(hdev, HCI_DEV_REG);
中間插入:
hdev->rfkill = rfkill_allocate(&hdev->dev, RFKILL_TYPE_BLUETOOTH);
if (hdev->rfkill) {
hdev->rfkill->name = hdev->name;
hdev->rfkill->toggle_radio = hci_rfkill_set_block;
hdev->rfkill->data = hdev;
if (rfkill_register(hdev->rfkill) < 0) {
rfkill_free(hdev->rfkill);
hdev->rfkill = NULL;
}
}

存檔完成hci_core.c檔案編輯。

步驟三,重新編譯Kernel
執行make clean及make開始編譯。


步驟四,編譯Android原始碼
1.參考: Bluetooth FAQ
https://sites.google.com/a/android.com/opensource/projects/bluetooth-faq
Q. How do I compile Android with Bluetooth support enabled?
A. Add this to your BoardConfig.mk:
BOARD_HAVE_BLUETOOTH := true

2.編輯init.rc加入 /sys/class/rfkill/rfkill0/state 可讀寫權限:
(android_source/system/core/rootdir/init.rc)
#bluetooth power up/down interface
chown bluetooth bluetooth /sys/class/rfkill/rfkill0/state
chmod 0660 /sys/class/rfkill/rfkill0/state

3.重新編譯Android原始碼後上載到開發平台上,測試看看在setting --> Wireless & network setting 將Bluetooth項目打勾就可以使用藍牙通訊了。
如果Bluetooth項目打勾沒有反應的話,在console下執行logcat確認是否/sys/class/rfkill/rfkill0/state檔案權限問題,如果為檔案權限問題ctrl-c離開logcat執行chmod 666 /sys/class/rfkill/rfkill0/state再進設定去將藍牙選項打勾應該就可以了。
上述步驟完成後,目前測試了藍牙GPS是可以接收到訊號,有時間再測試其他試試看。

參考:
Bluetooth FAQ
https://sites.google.com/a/android.com/opensource/projects/bluetooth-faq

4 則留言:

  1. 請問您這target platform?
    是Android?版本
    bluez又是版本?
    現在我新增build/target/board/generic/BoardConfig.mk,
    BOARD_HAVE_BLUETOOTH := true
    重新編譯Android原始碼
    就出錯

    target platform:mini6410
    android sdk:2.3.4
    bluez:4.6.9

    回覆刪除
  2. 我想請問一下,我現在的usb bluetooth 還是有權限上的問題
    需要進入adb 下chmod 666 /sys/class/rfkill/rfkill0/state
    的指令

    但是每次重開機 就得使用同樣的方式 下指令
    想請問 有沒有方法可以 讓他自動開啟 不需要每次都下指令才能啟動

    回覆刪除
  3. 2.編輯init.rc加入 /sys/class/rfkill/rfkill0/state 可讀寫權限:
    (android_source/system/core/rootdir/init.rc)
    #bluetooth power up/down interface
    chown bluetooth bluetooth /sys/class/rfkill/rfkill0/state
    chmod 0660 /sys/class/rfkill/rfkill0/state

    回覆刪除
  4. 不好意思 想問一下
    我的板子上就已經有藍芽的功能
    只是android沒辦法把它開起來

    不知道這篇的方法能不能套用在有藍芽的板子
    還是要再做些修改

    最近在研究 很多不懂
    希望能多請教

    回覆刪除