Km2Netの汎用USB-IOを動かす

汎用USB-IOはUSBインターフェースを使ったビットの入出力を扱う機器ですが、この機器はドライバを作成しなくても操作することが出来たりということで意外と便利な代物だったので、これをFreeBSD上で動かしたときのメモを記載しています。
尚、ここで記載している内容はKm2Netさんで販売されていた汎用USB-IO(写真)を前提にしています。



作成日:2008.7.11
更新日:2008.10.7

前提条件
これを行ったときの環境を以下のようにしています。
■環境
・libusb-0.1.12_1
・FreeBSD-6.2
そんなに無いとは思いますがもしかしたらlibusbがバージョンによって処理方法が変わるかもしれませんのでここのバージョンと違う場合は更新履歴をチェックしておいた方が良いかもしれません。
ちなみにlibusbはC言語でUSB機器へアクセするための関数を収録したGPLライセンスのライブラリでこれを活用することで簡単にUSB機器を操作することが出来ます。
ページのトップへ

カーネルの再構築
この機器をUSBに差し込むと"uhid"で認識されるのですが、操作するために利用するlibusbが"ugen"でないと出来ないので"uhid"を無効にするためにカーネルの再構築を行います。

まずはカーネルの該当箇所を書き換えます。
"/usr/src/sys/i386/conf/GENERIC"
(色分け:書換追記コメント)
261: # USB support
262: device uhci # UHCI PCI->USB interface
263: device ohci # OHCI PCI->USB interface
264: device ehci # EHCI PCI->USB interface (USB 2.0)
265: device usb # USB Bus (required)
266: #device udbp # USB Double Bulk Pipe devices
267: device ugen # Generic
268: #device uhid # "Human Interface Devices"
※コメントアウトにする

269: device ukbd # Keyboard
270: device ulpt # Printer
271: device umass # Disks/Mass storage - Requires scbus and da
272: device ums # Mouse
273: device ural # Ralink Technology RT2500USB wireless NICs
274: device urio # Diamond Rio 500 MP3 player
275: device uscanner # Scanners
書き換えたら再構築を行います。
(色分け:入力値コマンドラインコメント)
# config GENERIC
Kernel build directory is ../compile/GENERIC
Don't forget to do ``make cleandepend; make depend''

# cd ../compile/GENERIC

# make cleandepend ; make depend ; make clean ; make

エラーがなければインストール
# make install
あとは再起動して"ugen"として認識されていれば問題有りません。
ページのトップへ

インストール
カーネルの再構築が終われば次はlibusbをインストールします。
(色分け:入力値コマンドラインコメント)
# portinstall libusb

---> Session started at: Thu, 24 Apr 2008 19:25:42 +0900
Install 'devel/libusb'? [yes]
[Gathering depends for devel/libusb . done]
---> Fresh installation of devel/libusb started at: Thu, 24 Apr 2008
19:25:44 +0900
---> Installing 'libusb-0.1.12_1' from a port (devel/libusb)
---> Build of devel/libusb started at: Thu, 24 Apr 2008 19:25:44
+0900
---> Building '/usr/ports/devel/libusb'
===> Cleaning for libusb-0.1.12_1
===> Vulnerability check disabled, database not found
===> Found saved configuration for libusb-0.1.12_1
=> libusb-0.1.12.tar.gz doesn't seem to exist in /usr/ports/distfile
s/
=> Attempting to fetch from http://heanet.dl.sourceforge.net/sourcefo
rge/libusb/.
libusb-0.1.12.tar.gz 100% of 380 kB 120 kBps
===> Extracting for libusb-0.1.12_1
=> MD5 Checksum OK for libusb-0.1.12.tar.gz.
=> SHA256 Checksum OK for libusb-0.1.12.tar.gz.
===> Patching for libusb-0.1.12_1
===> Applying FreeBSD patches for libusb-0.1.12_1
===> libusb-0.1.12_1 depends on file: /usr/local/bin/libtool - foun
===> Configuring for libusb-0.1.12_1

... (中略) ...

Libraries have been installed in:
/usr/local/lib

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
- add LIBDIR to the `LD_LIBRARY_PATH' environment variable
during execution
- add LIBDIR to the `LD_RUN_PATH' environment variable
during linking
- use the `-Wl,--rpath -Wl,LIBDIR' linker flag

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------
test -z "/usr/local/include" || /var/tmp/usr/ports/devel/libusb/work/
libusb-0.1.12/install-sh -d "/usr/local/include"
install -o root -g wheel -m 444 'usbpp.h' '/usr/local/include/usbpp.
h'
test -z "/usr/local/include" || /var/tmp/usr/ports/devel/libusb/work/
libusb-0.1.12/install-sh -d "/usr/local/include"
install -o root -g wheel -m 444 'usb.h' '/usr/local/include/usb.h'
test -z "/usr/local/libdata/pkgconfig" || /var/tmp/usr/ports/devel/li
busb/work/libusb-0.1.12/install-sh -d "/usr/local/libdata/pkgconfig"
install -o root -g wheel -m 444 'libusb.pc' '/usr/local/libdata/pkg
config/libusb.pc'
Making install in tests
Making install in doc
===> Running ldconfig
/sbin/ldconfig -m /usr/local/lib
===> Registering installation for libusb-0.1.12_1
===> Cleaning for libusb-0.1.12_1
---> Installation of devel/libusb ended at: Thu, 24 Apr 2008 19:26:14
+0900 (consumed 00:00:04)
---> Saving the log as '/var/log/ports/portupgrade-devel::libusb.log'
---> Fresh installation of devel/libusb ended at: Thu, 24 Apr 2008
19:26:14 +0900 (consumed 00:00:29)
---> ** Install tasks 1: 1 done, 0 ignored, 0 skipped and 0 failed
---> Listing the results (+:done / -:ignored / *:skipped / !:failed)
+ devel/libusb
---> Packages processed: 1 done, 0 ignored, 0 skipped and 0 failed
---> Saving the results to '/var/ports/result'
---> Session ended at: Thu, 24 Apr 2008 19:26:14 +0900 (consumed 00:
00:31)
インストール後は"/usr/local/include"に"usb.h"が作成されますので、プログラミング時にはこのファイルをインクルードして利用します。
libusbに関するドキュメントはここに記載されています(かなり簡易で書かれていますので少し分かりづらいところもありますが)
ページのトップへ

編集&コンパイル
あとは実際に動かすためのプログラムをCで書けば良いのですが全てを一から書くのはかなり難儀なことなので「バケさんの趣味の部屋」で公開されていたプログラムを活用させて貰っています。

ダウンロードしてくるファイルは「Linux(FC6,FC5)で汎用USB-IO(ビット操作)サンプル 」にある"musbiobase.h"と"usbio.c"の2つでこれを適当なディレクトリに保存します。

で、あとはこれをコンパイルするだけなのですが、その前にいくつか編集しないといけないのでまずそれを行います。

[musbiobase.hのダウンロードはここから出来ます]
(改変したソースファイルは事前にバケさんの了解を得た上で公開しています)
"musbiobase.h"
(色分け:書換追記コメント)
 1: /* For TECHNO KIT */
2: // #define USB_VENDOR 0x12ed
3: // #define USB_PRODUCT 0x1003
4: /* For USB-An */
5: #define USB_VENDOR 0x1352
6: #define USB_PRODUCT 0x0100
TECHNOKIT側をコメントアウトしてUSB-Anを有効にする。
(USB-AnとUSB-IOは同じID)

... (中略) ...

33: /* USBIO Open */
34: struct usb_dev_handle *morphy_open(struct usb_device *dev)
35: {
36: struct usb_dev_handle *udev = NULL;
37:
38: udev=usb_open(dev);
39: if( udev==NULL ){
2重OpenになっていたためかここでエラーになるのでIf分の条件を変更。

40: printf("usb_open Error.(%s)\n",usb_strerror());
41: exit(1);
42: }
43:
44: if( usb_set_configuration(udev,dev->config->bConfigurationValue)<0 ){
45: // if( usb_detach_kernel_driver_np(udev,dev->config->interface->altsetting->bInterfaceNumber)<0 ){
46: printf("usb_set_configuration Error.\n");
47: // printf("usb_detach_kernel_driver_np Error.(%s)\n",usb_strerror());
48: // }
49: }
50:
51: if( usb_claim_interface(udev,dev->config->interface->altsetting->bInterfaceNumber)<0 ){
52: // if( usb_detach_kernel_driver_np(udev,dev->config->interface->altsetting->bInterfaceNumber)<0 ){
53: printf("usb_claim_interface Error.\n");
54: // printf("usb_detach_kernel_driver_np Error.(%s)\n",usb_strerror());
55: // }
56: }
FreeBSDではusb_detach_kernel_driver_np関数が非対応なのでそれに処理
をコメントアウトにする。

57:
58: if( usb_claim_interface(udev,dev->config->interface->altsetting->bInterfaceNumber)<0 ){
59: printf("usb_claim_interface Error.(%s)\n",usb_strerror());
60: }
usb_detach_kernel_driver_np関数はLinux専用でFreeBSDでは非対応なのでコメントアウトしておかないと下のようなエラーが表示されます。
gcc -o usbio usbio.c -I/usr/local/include -L/usr/local/lib -lusb
/var/tmp//ccP6qz5j.o(.text+0x11a): In function `morphy_open':
: undefined reference to `usb_detach_kernel_driver_np'
/var/tmp//ccP6qz5j.o(.text+0x190): In function `morphy_open':
: undefined reference to `usb_detach_kernel_driver_np'
*** Error code 1

Stop in /root/usbio.

編集が終わればコンパイルを行います。
(色分け:入力値コマンドラインコメント)
(実際には1行)
# gcc -o usbio usbio.c -I/usr/local/include -L/usr/local/lib
-lusb

[オプション]
-o --- 出力先※/root/usbioに保存していることにします
-I --- ヘッダーファイルがある場所を指定
-L --- ライブラリがある場所を指定
-l --- リンクするライブラリ名
usbioというファイルが作成されていれば問題ありません。
ページのトップへ

動作確認&起動方法
コンパイルが終われば、そのプログラムに必要なオプションを付けて実行することで取得したり出力したり出来ます。

■ヘルプの表示(引数を付けずに実行)
(色分け:入力値コマンドラインコメント)
# ./usbio
Usage:
usbio -h|-l|-i -p0|-p1 [-bn]
-h : Set Hi // Hi出力(V+)
-l : Set Lo // Lo出力(0V)
-i : Get Status // 状態の取得
-p0 : Select Port0 // ポート0を選択
-p1 : Select Port1 // ポート1を選択
-bn : Select Bit No // ビット選択
n= 0..7 (If select -p1 then n= 0..3)
If not set -bn then All Data in Select Port

※1番目、2番目の引数は必須で3番目は必要に応じて指定する

■状態の取得
(色分け:入力値コマンドラインコメント)
# ./usbio -i -p0
Port0 : 17
※2進数8ビットを10進数で表示している。
ここで取得される数値はポート0の2進数8ビット構成を10進数に変換した値で、例えば、17と表示されていれば0ビット目と5ビット目がHiになりあとはLowになっていることを意味します。
ちなみにKm2NetのUSB-IOではポート0(8ビット)+ポート1(4ビット)の12ビットが扱えます。

■ポート0の3ビット目の状態を取得
(色分け:入力値コマンドラインコメント)
# ./usbio -i -p0 -b3
Port03 : h
※h : High出力, l : Low出力

■Hi出力
(色分け:入力値コマンドラインコメント)
# ./usbio -h -p0
Port0 : 255
ページのトップへ

補足&メモ
ポート0は8ビット全部あるので問題ないのですが、ポート1は8ビット中4ビットのみとなっていて足りないビット分はHi,Low出力した時の状態に固定されるのでビットではなくポート単位のデータを取り扱う場合はこの辺に注意する必要があります。
また、今回利用したサンプルソースは公開されている時点で既に完成度が高いと思いますので、あとは応用系のソフトウェアを作って連携させればかなり幅が広がりそうです。
ページのトップへ