2015/02/21

[libusb]usbviewとlibusbのこまごまとした違い (1)

【これまでのあらすじ】
あるUSBデバイスをlibusbで見てみよう、と軽く考えたhiro99ma。
いつものようにzadigでWinUSBドライバに変更したものの、libusbのオープンすらできない。
どうもEnumerationあたりに原因がありそうなのだが・・・・?

 

まだ解決には至っていないが、整理がてらメモを残しておく。

今はWinUSBのサンプルとしてusbviewを見つつ、libusbのEnumerationとどう違うのかを見ていっている。
一応、私のUSBスキルの話をしておくと、無いに等しい。
ときどきネタとしてlibusbのことを書いているが、だいたいは動いている前提でバルク転送するだけしかやってないのだ。
動かないときはzadigでドライバを差し替えるだけ。
今回のように、実装にせよ内部のことを見るのははじめてだ。

で、素人っぽくAPIの使い方を見ていったのだが、そんなに違いはなさそう。
ただ、APIに渡すパラメータがいくつか違う。

最初に気付いた違いは、サイズだ。
libusbはUSB_NODE_CONNECTION_INFORMATION_EXのsizeofをそのまま設定しているのだが、usbviewではsizeof(USB_NODE_CONNECTION_INFORMATION_EX) + (sizeof(USB_PIPE_INFO) * 30)という大きい値を渡している。
なんかUSB_NODE_CONNECTION_INFORMATION_EX構造体の定義を見ると、こうなってた。

typedef struct _USB_NODE_CONNECTION_INFORMATION_EX {
  ・・省略・・
  USB_PIPE_INFO PipeList[0];
}USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX;

確かこの記述方法は、C99あたりで採用されたものじゃなかったろうか。
つまり、一番最後に可変なメンバを置き、malloc()などでサイズを自由に確保するやつだ。

大ざっぱな書き方をすると、こんな感じか。

struct image_x {
  uint8_t r;
  uint8_t g;
  uint8_t b;
  uint8_t alpha;
};

struct image {
  int width;
  int height;
  image_x  pix[0];
};

int width = どっかから横幅を取得;
int height = おなじく縦幅を取得;
image *pImageArray = (image *)malloc(sizeof(image) + sizeof(image_x) * width * height));

なんとなく、イメージが伝わればよいが。
以前は、配列要素に「0」を指定できなかったので、上記をこうやって書いていたそうだ。

int width = どっかから横幅を取得;
int height = おなじく縦幅を取得;
image *pImageArray = (image *)malloc(sizeof(image) + sizeof(image_x) * (width – 1) * height));

[1]とする以上、1つ分のメモリは確保されるので、それを差し引いた分を確保するという意味だ。

 

細かい中身はよいとして、比較で気になったのは、libusbはこのメンバをスタックで確保していたのに対し、usbviewはポインタで確保してmalloc()で割り当てていたというところだ。
だから、IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EXで取得した値すべてを渡すにはメモリが足らずに失敗していた、という筋書きじゃなかろうかと。

・・・違うね。
少なくとも、サイズだけが原因ではないようだった(暫定でメモリを増やして試した)。
DeviceIoControl()自体は成功していて、このデバイスに対しては戻ってきたサイズが小さいものなぁ。

 

今回は私の負けだが、それで終わりではないぞ。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。