結局は自分のしょーもないポカミスなんだけれど、ある掲示板で同じようなことを質問していた人がいたのと、ちょっと気づきにくいミスなので、備忘録の意味も含めて書き留めておく。
WinUSBを使ってUSB通信を行うとき、ベンダspecificなリクエストを送信するコントロール転送を行うのに、
SendVendorSpecificRequest_in()とSendVendorSpecificRequest_out()と名前の関数を用意してこれを呼び出すようにしていた。
問題の始まりはコントロールOUT転送を行うSendVendorSpecificRequest_out()関数の引数の型だった。
これは送信を行う関数になるので、DATAステージのデータをconst void* なポインタで渡すようプロトタイプ宣言していた。つまり、
bool SendVendorSpecificRequest_out(
...,
const void* dat, // DATAステージで出力するconstなデータ
int len, // DATAステージで出力するデータ長さ
...);
という感じ(他の引数は省略)。
こういう関数を用意すると、この関数の呼び出し側では
static const char text_data[] = "hogehoge";
SendVendorSpecificRequest_out(
...,
text_data,
strlen(text_data),
...);
みたいな呼び出しができる訳だけれど、これが間違い。
それはこの関数の中身の実装がこうなっていたから。
BOOL SendVendorSpecificRequest_out(
...,
const void* dat,
int len, ...)
{
WINUSB_SETUP_PACKET setup_pkt;
setup_pkt.RequestType = 0x40 or 0xC0;
setup_pkt.Request = リクエストコード;
setup_pkt.Value = wValueの値;
setup_pkt.Index = wIndexの値;
setup_pkt.Length = len;
ULONG sent;
return WinUsb_ControlTransfer(
WinUSBハンドル,
setup_pkt,
(PUCHAR)dat,
len,
&sent,
NULL);
}
WinUsb_ControlTransfer()の第三引数を無理矢理PUCHARにキャストしているところが間違い。
コントロールOUT転送だからWinUsb_ControlTransfer()関数は第三引数で示されるポインタを使ってreadしか行わないだろう(=read属性のみのメモリを渡してもキャストしておけば大丈夫)と思っていたら、内部の実装はそうではないようだ。コントロールOUT転送でもここで渡すポインタは必ずread-write可能なメモリのポインタを渡さなければならない。
という訳で回避策は、WinUsb_ControlTransfer()関数に渡す前に別のread-write可能なバッファにコピーしてから呼び出すか、そもそもSendVendorSpecificRequest_out()関数のプロトタイプからconst修飾子自体を取ってしまって、constなポインタは渡せないようにするか・・・。
0 件のコメント:
コメントを投稿