Bluetooth詳説
Bluetoothプロトコルの解説とライブラリ開発
ホーム  :  検索  :  記事一覧  :  RSSフィード  :  リンク  :  ダウンロード  
 2010年09月 9日(木曜日) 08:51 JST

Linux USBドライバ

   
開発

購入したBluetooth USBアダプター "PLANEX BT-Mini2EDR" を制御するUSBドライバをこれから作成していきます。

まずはLinux USBドライバの仕組みを知る必要があるわけですが、作成にあたって下記を参考にします。

書籍

Linuxデバイスドライバ 第3版
この本の第2版を持っています。
Linuxデバイスドライバ全般に関して網羅的に恐ろしく詳細に説明されていますが、残念ながらUSBドライバに関する記述は少ししかありません。
(追記)第3版ではKernel2.6に対応しただけでなく、USBドライバに1つの章が割かれて、USBドライバ作成に関する記述が大幅に増えています。
値段が高いのが難点ですが、この書籍の情報が最も参考になるでしょう。
英語で読む労力を惜しまないならば、オンラインバージョンが用意されています。

Webページ

Writing a Simple USB Driver
簡単なUSBドライバのサンプルが英語で解説されています。
USB-CAMAC デバイスドライバ
Kernel2.4でのLinux USBドライバフレームワークの日本語解説があります。
画像が表示されなかったりしますので、メンテナンスされていないようです。

参考ソースコード

(例) KERNEL_SRC = /usr/src/linux

$(KERNEL_SRC) /drivers/usb/usb-skeleton.c
Linuxカーネルソースが提供するUSBドライバのスケルトンコードです。
$(KERNEL_SRC) /drivers/bluetooth/hci_usb.c, hci_usb.h
$(KERNEL_SRC) /include/net/bluetooth/bluetooth.h, hci_core.h
$(KERNEL_SRC) /net/bluetooth/hci_core.c
BlueZのBluetooth USBドライバと関連コードです。

それでは、とりあえず何もしない独自スケルトンコードを書いてみます。

>> 続く



Vendor IDとProduct ID

USBデバイスにはVendorI DとProduct IDが割り振られています。
USBドライバでは、ドライバがサポートする機器のVendor IDとProduct IDを指定しますので、まずはこの情報を取得します。

$ cat /proc/bus/usb/devices

を実行すると、接続されているUSB機器の情報が表示されます。
PCに備わっているUSBハブなどの情報も表示されるのですが、その中でBluetooth USBアダプターの情報だけを抜き出したものが以下です。

T:  Bus=04 Lev=01 Prnt=01 Port=01 Cnt=02 Dev#=  3 Spd=12  MxCh= 0
D:  Ver= 2.00 Cls=e0(unk. ) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=0a12 ProdID=0001 Rev=19.58
C:* #Ifs= 2 Cfg#= 1 Atr=c0 MxPwr=  0mA
I:  If#= 0 Alt= 0 #EPs= 3 Cls=e0(unk. ) Sub=01 Prot=01 Driver=(none)
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=1ms
E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
I:  If#= 1 Alt= 0 #EPs= 2 Cls=e0(unk. ) Sub=01 Prot=01 Driver=(none)
E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
I:  If#= 1 Alt= 1 #EPs= 2 Cls=e0(unk. ) Sub=01 Prot=01 Driver=(none)
E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
I:  If#= 1 Alt= 2 #EPs= 2 Cls=e0(unk. ) Sub=01 Prot=01 Driver=(none)
E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
I:  If#= 1 Alt= 3 #EPs= 2 Cls=e0(unk. ) Sub=01 Prot=01 Driver=(none)
E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
I:  If#= 1 Alt= 4 #EPs= 2 Cls=e0(unk. ) Sub=01 Prot=01 Driver=(none)
E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
I:  If#= 1 Alt= 5 #EPs= 2 Cls=e0(unk. ) Sub=01 Prot=01 Driver=(none)
E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms

インターフェースとエンドポイントに関する情報なども含まれていますが、情報の中にVendor=0a12 ProdID=0001という記述があります。
つまりVendor ID = 0x0a12, Product ID = 0x0001ということです。

ソースコード

作成するスケルトンドライバは、デバイスが挿入されたときと取り外されたときにメッセージを吐き出すだけで、何もしません。

以下がソースコード全体です。ファイル名はsimple_usb.cです。

/* 
   Simple USB driver for Linux
   Copyright (C) 2006 Lily <bt@k5-n.com>

   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;

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
   SOFTWARE IS DISCLAIMED.
*/

#include <linux/usb.h>

/*
 * 定数とマクロ
 */

/* ドライバのバージョン */
#define VERSION "0.1"

/* このドライバがサポートするデバイスのベンダーIDとプロダクトID */
#define VENDOR_ID   0x0a12    /* TODO ドライバがサポートする機器に合わせて変更 */
#define PRODUCT_ID  0x0001   /* TODO ドライバがサポートする機器に合わせて変更 */

/*
 * 関数宣言
 */

static int simple_usb_probe(struct usb_interface *intf, const struct usb_device_id *id);
static void simple_usb_disconnect(struct usb_interface *intf);
static int __init simple_usb_init(void);
static void __exit simple_usb_exit(void);

/*
 * データ定義
 */

/* このドライバを利用する機器のリスト */
static struct usb_device_id simple_usb_id_table[] = {
        { USB_DEVICE(VENDOR_ID, PRODUCT_ID) },
        { },
};
MODULE_DEVICE_TABLE (usb, simple_usb_id_table);

/* USBドライバ構造体 */
static struct usb_driver simple_usb_driver = {
    .name       = "simple_usb",
    .probe      = simple_usb_probe,
    .disconnect = simple_usb_disconnect,
    .id_table   = simple_usb_id_table,
};

/*
 * 関数定義
 */

/* デバイスが接続されるたびに呼び出される */
static int simple_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
    info("Probed");

    return 0;
}

/* デバイスが取り外されるたびに呼び出される */
static void simple_usb_disconnect(struct usb_interface *intf)
{
    info("Disconnected");
}

/* ロードされた時にモジュールを初期化する */
static int __init simple_usb_init(void)
{
    int ret;

    info("Simple USB Driver ver %s", VERSION);

    ret = usb_register(&simple_usb_driver);
    if (ret < 0) {
        err("usb_register faild. Error Number = %d", ret);
    }

    return ret;
}

/* モジュールを削除する直前に呼ばれる */
static void __exit simple_usb_exit(void)
{
    usb_deregister(&simple_usb_driver);
    info("Simple USB Driver deregistered");
}

/*
 * ドライバ情報の登録
 */

/* 初期化関数、終了関数の登録 */
module_init(simple_usb_init);
module_exit(simple_usb_exit);

MODULE_AUTHOR("Lily <bt@k5-n.com>");
MODULE_DESCRIPTION("Simple USB driver ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");

ドライバがロードされたときに呼び出される関数は、module_initで指定します。
このソースの例ではsimple_usb_initという関数を指定しています。
ドライバがアンロードされたときに呼び出される関数は、module_exitで指定します。
このソースの例ではsimple_usb_exitという関数を指定しています。

USBドライバの情報はusb_driver型の構造体に設定します。
ドライバの名前、デバイスが接続されたときに呼び出される関数、デバイスが取り外されたときに呼び出される関数、サポートするデバイスのリストを設定します。

コンパイル

「Linuxデバイスドライバ(第2版)」に書いてあるMakefileではコンパイルできませんでした。
どうやらKernel2.6では仕様が変わっているようです。

Driver porting: compiling external modules
によると、幾つか必要なことが増えているとのこと。
今後変更になるかもしれないコンパイル手順を追いかけるより、カーネルソースのコンパイルの仕組を借りてコンパイルした方が良いとして、その場合のMakefileの書き方が載っています。

この方法でMakefileを作成しました。以下がMakefileの内容です。

ifneq ($(KERNELRELEASE),)
obj-m   := simple_usb.o
else
KDIR    := /lib/modules/$(shell uname -r)/build
PWD     := $(shell pwd)

default:
    $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
endif

clean:
    rm *.o *.ko *~ core

動作確認

# insmod simple_usb.ko

でモジュールをロードします。この時点で

# dmesg

の結果には以下が追加されます。

/home/lily/work/bluetooth/blacktooth/drivers/simple/simple_usb.c: Simple USB Driver ver 0.1
usbcore: registered new driver simple_usb

次にBluetooth USBアダプターを接続すると、以下がdmesgに追加されます。

usb 3-2: new full speed USB device using uhci_hcd and address 3
usb 3-2: configuration #1 chosen from 1 choice
/home/lily/work/bluetooth/blacktooth/drivers/simple/simple_usb.c: Probed
/home/lily/work/bluetooth/blacktooth/drivers/simple/simple_usb.c: Probed

さらにBluetooth USBアダプターを取り外すと、以下がdmesgに追加されます。

usb 3-2: USB disconnect, address 3
/home/lily/work/bluetooth/blacktooth/drivers/simple/simple_usb.c: Disconnected
/home/lily/work/bluetooth/blacktooth/drivers/simple/simple_usb.c: Disconnected

# rmmod simple_usb

でドライバモジュールを削除すると、以下がdmesgに追加されます。

usbcore: deregistering driver simple_usb
/home/lily/work/bluetooth/blacktooth/drivers/simple/simple_usb.c: Simple USB Driver deregistered

どうやら各関数はちゃんと呼び出されているようです。
ただ何故probeとdisconnectが2回呼び出されるかは謎(^^;)です。
それは開発しながらおいおい調べていくということで、とりあえず。

 

関連情報

記事のオプション

トラックバック

このエントリのトラックバックURL: http://bluetooth.k5-n.com/trackback.php?id=2007011323305764

Linux USBドライバ | 0 件のコメント | アカウントの作成
コメントは投稿者の責任においてなされるものであり、サイト管理者は責任を負いません。
 Copyright © 2010 Bluetooth詳説
 本ページのすべての商標と著作権はそれぞれの所有者に帰属します。
Powered By Geeklog & Geeklog Japanese
ページ作成時間: 0.17 秒