2015年4月17日金曜日

EZ-USB FX2LP を動かしてみる (21) open()とclose()とstring descriptor

前回、Linuxマシンに接続されている全てのデバイスディスクリプタを読めました.今回は、open() close()してみるとともに、ストリングディスクリプタを読んでみようと思います.

libusbの関数のあり方から推測すると、open()してからでないとストリングディスクリプタを読めないみたいです.

何をやったか?
ソースコードはこちらです.

Linuxマシンで、コンパイルします.
gcc fx2b.c -lusb
出来たa.outを実行しますと、このような表示が出ます.各USBデバイス毎にこのような表示が出ますので、結構長いです.これはEZ-USB FX2LPについての表示結果で、VID/PID=04B4/1004になっています.また、ストリングディスクリプタには、CypressとESZ-USBの文字が見えます.FX2LPのストリングディスクリプタについてはこちらで少し触れました.確かにCypressの文字が実装されています.
===device descriptor===    ここからデバイスディスクリプタの内容
 Length 18
    中略
 Config Num 1
===config descriptor===    ここからコンフィグデスクリプタの内容
 Length 9
    中略
 MaxPower 100mA
-->device open                 デバイスをopenしてみる
 -->open successfully          open成功
===string descr (Index0)           以下、ストリングディスクリプタをGETしてみる
===string descr (Index1)Cypress
===string descr (Index2)EZ-USB
===string descr (Index3)
===string descr (Index4)
===string descr (Index5)
===string descr (Index6)
===string descr (Index0)?         別の関数でストリングディスクリプタをGETしてみる
===string descr (Index1)Cypress
===string descr (Index2)EZ-USB
===string descr (Index3)
===string descr (Index4)
===string descr (Index5)
===string descr (Index6)

ソースコードの概説
open,close,get stringがここでの要点です.

#include <usb.h>     libusbを使うための構造体や関数の定義

int main()
{
 char str[100];    ストリングディスクリプタを読み込む文字バッファ(とりあえず100バイト)

 for(bus=bus; bus; bus=bus->next){    全てのUSBバスをなめる
  for(dev=bus->devices; dev; dev=dev->next) {     全てのUSBデバイスをなめる
       中略
    h_dev=usb_open(dev);     片っ端からUSBデバイスをOPENしてみる
    if(h_dev==NULL){
     printf(" -->cannot open\n");     OPENできなければ断念する
    }
    else {
     for(k=0;k<=6;k++) {   何個あるか不明なストリングディスクリプタを7ヶ読んでみる
      i=usb_get_string(h_dev,k,0,str,100);    ストリングディスクリプタGETの関数1
      printf("===string descr (Index%d)",k);
      for(j=2;j<i;j++) if(str[j]!=0) printf("%c",str[j]);    ストリングディスクリプタ表示
      printf("\n");
     }

     for(k=0;k<=6;k++) {   何個あるか不明なストリングディスクリプタを7ヶ読んでみる
      i=usb_get_string_simple(h_dev,k,str,100);    ストリングディスクリプタGETの関数2
      printf("===string descr (Index%d)",k);
      for(j=0;j<i;j++) if(str[j]!=0) printf("%c",str[j]);    ストリングディスクリプタ表示
      printf("\n");
     }
     usb_close(h_dev);    用済みなのでcloseする
    }
  }
 }
 return 0;
}

考察
表示されたストリングディスクリプタから、Linuxマシンに接続されているデバイスを推測してみます.ストリングディスクリプタが空欄のデバイスもありましたので、これは一部です.USBマウスのストリングディスクリプタは空欄のようでした.デバイスディスクリプタを細かく見ればUSBマウスが存在するはずです.

これはPCIにUSBが接続されている部分かな?
===string descr (Index2)OHCI PCI host controller
===string descr (Index3)Linux 3.16.0-4-amd64 ohci_hcd

これは、秋月のUSBシリアルです.
===string descr (Index1)Prolific Technology Inc.
===string descr (Index2)USB-Serial Controller

これは無線キーボードの受信機です.
===string descr (Index1)Logitech
===string descr (Index2)USB Receiver

これは無線キーボード本体.
===string descr (Index2)USB Keyboard

これはEZ-USB FX2LP
===string descr (Index1)Cypress
===string descr (Index2)EZ-USB

このようにいろいろなUSBデバイスが検出されました.

ここで疑問
Q: 上記USBデバイスは稼動中ですが、これらをlibusbからopen()したらどうなるんだろ???
A: なにげにopenできてしまいました.それって二重OPENかしら? 本当はOPEN出来てはイケナイのだろうけど、libusbが裏から手を回したらOPEN出来ちゃうんだろう.ちなみに、OPENしたからといってKBDが誤動作したりはしませんでした.

ここで疑問
Q: OPENしないとストリングディスクリプタをGETできないの?
A: open()の返値をget_string()の引数に使っているので、OPENしないとダメっぽい.

ここで疑問
Q: ストリングディスクリプタは何個もあるが、総数何個なのかはデバイスによりけり.総数何個かはどこかに記述されているのだろうか?
A: これはよくわかってません.事実としては、どれも0番目は空欄(0x04,0x09のみ)です.1番目と2番目あたりに、文字が書かれているケースが多い.それ以降の番目を読むと、返値=2が返ってくるけど空欄みたいな状況.
 ===string descr (Index0)
 ===string descr (Index1)Cypress    ←デバイスディスクリプタManufacturerが指す「1」
 ===string descr (Index2)EZ-USB   ←デバイスディスクリプタProductが指す「2」
 ===string descr (Index3)
 ===string descr (Index4)
 ===string descr (Index5)
 ===string descr (Index6)
追記: わかりました.デバイスディスクリプタの中にIndex番号が書かれています.
 ===device descriptor===
 Manufucturer 1    →上記の「Cypress」を指す
 Product 2          →上記の「EZ-USB」を指す
 SerianNum 0      →ゼロはemptyの意味かな?

ここで疑問
Q: FX2LPのストリングディスクリプタはC言語のstringとは違うけど? こんな格納になってる.
      db   'C',00    ←1文字毎に00が挿入されている
      db   'y',00
      db   'p',00
      db   'r',00
      db   'e',00
      db   's',00
      db   's',00
A: ホストがGETしたストリングディスクリプタも同様です.なので、printf()する時に00は無視して表示しています.

【usb_get_string()の解説】
ストリングディスクリプタをGETする関数で、
i = usb_get_string(h_dev,k,0,str,100);
のように使います.
返値iはstrに格納したデータ個数(BYTE)です.最低でも2が返されます.str[0]はレングスで、str[1]はストリングディスクリプタであるコード(常に3)です.
h_devはusb_open()の返値で、デバイスへのハンドルです.
kは、何個目のストリングディスクリプタをGETしたいかの番号.
0は、言語コードですが、いつも0でいいんじゃね?
strは、GETした文字列を入れるところ.文字データはstr[2]以降に格納されます.
100は、GETしたいバイト数.

ここで疑問
Q: str[]はどれだけのサイズを確保しておくべきかねぇ?
A: レングスフィールドが8bitなのでstr[256]でよいのではないかと思ってみたりする.

【usb_get_string_simple()の解説】
ストリングディスクリプタをGETする関数で、
i = usb_get_string_simple(h_dev,k,str,100);
のように使います.
言語コードが省略されています.
str[0]から文字が格納されて戻って来ます.

その20へ    その22へ

かしこ

INDEXページへ
https://hirasakausb.blogspot.com/2019/03/ez-usb-fx2lp-index.html

0 件のコメント:

コメントを投稿