Hi there,

I'm recently developing a program running on Linux
that talks to a USB Bulk-Only Mass Storage device.

I know there's a usb-storage driver can handle all the
read/write stuff, while I need to send some extra
"vendor commands" to the device.

So I try libusb, but I encounter problems.
I try to send an 31 bytes CBW to the device, and listen
to the bytes returned. I got none.
The usb_bulk_read return 0.

In a normal TestUnitReady once a 31 bytes TestUnitRead
has given, a 13 bytes CSW should be returned.

I tried usb_set_configuration and usb_set_altinterface. No use.

My kernel is Linux 2.4.20-8, RedHat 9.
and libusb version is 0.1.12.

any one has any suggestion with it?

below is my code
#include "bulkusb.h"

#define DEBUG_MSG

#define COMMAND_TIMEOUT 5000

enum {
DATA_IN,
DATA_OUT
};

usb_dev_handle *pHandle;

int BulkIN_EP;
int BulkOUT_EP;

int
BulkUSB_Open(struct usb_device *pDev)
{

int i;
char string[256];

pHandle = NULL;

pHandle = usb_open(pDev);
if (pHandle) {
usb_get_driver_np(pHandle, 0, string, 256);
if (strcmp(string, "usb-storage") == 0) {

if(usb_detach_kernel_driver_np(pHandle, 0)<0){
#ifdef DEBUG_MSG
printf("usb_detach_kernel_driver_np fail\n");
#endif
}

/*
if(usb_set_configuration(pHandle, 1)<0){
#ifdef DEBUG_MSG
printf("usb_set_configuration fail\n");
#endif
}
*/

/*
if(usb_set_altinterface(pHandle, 1)<0){
#ifdef DEBUG_MSG
printf("usb_set_altinterface fail\n");
#endif
}

*/
if (usb_claim_interface(pHandle, 0)) {
#ifdef DEBUG_MSG
printf("usb_claim_interface fail\n");
#endif
usb_attach_kernel_driver_np(pHandle, 0);
usb_close(pHandle);
return 0;

} else {
if (pDev->config[0].interface[0].altsetting[0].endpoint[0].
bEndpointAddress & 0x80) {
BulkIN_EP =
pDev->config[0].interface[0].altsetting[0].
endpoint[0].bEndpointAddress;
BulkOUT_EP =
pDev->config[0].interface[0].altsetting[0].
endpoint[1].bEndpointAddress;
} else {
BulkIN_EP =
pDev->config[0].interface[0].altsetting[0].
endpoint[1].bEndpointAddress;
BulkOUT_EP =
pDev->config[0].interface[0].altsetting[0].
endpoint[0].bEndpointAddress;
}
return 1;
}
} else {
return 0;
}
} else {
return 0;
}
}

void
BulkUSB_Close()
{
if (pHandle) {
usb_release_interface(pHandle, 0);
usb_attach_kernel_driver_np(pHandle, 0);
usb_close(pHandle);
}
}

int
BulkUSB_Read(int ReadDataLen, unsigned char *pReadData)
{

int r_value;

if (!pHandle) {
return 0;
}

//usb_set_configuration(pHandle, 1);
usb_set_altinterface(pHandle, 0);

r_value =
usb_bulk_read(pHandle, BulkIN_EP, pReadData, ReadDataLen,
COMMAND_TIMEOUT);

if (r_value < 0) {
return 0;
} else {

#ifdef DEBUG_MSG
printf("read %d bytes\n", r_value);
#endif
return 1;
}

}

int
BulkUSB_Write(int WriteDataLen, unsigned char *pWriteData)
{

int r_value;

if (!pHandle) {
return 0;
}

//usb_set_configuration(pHandle, 1);
//usb_set_altinterface(pHandle, 0);

r_value =
usb_bulk_write(pHandle, BulkOUT_EP, pWriteData, WriteDataLen,
COMMAND_TIMEOUT);

if (r_value < 0) {
return 0;
} else {
#ifdef DEBUG_MSG
printf("write %d bytes\n", r_value);
#endif
return 1;
}

}

int
BulkUSB_ExecCBWCB(unsigned char *pCBWCB, unsigned char Dir,
unsigned char *pDataBuf, int DataBufLen)
{

int r_value;
unsigned char CBW[31];
unsigned char CSW[13];

if (!pHandle) {
return 0;
}

memset(CBW, 0x00, 31);
memset(CSW, 0x00, 13);

// dCBWSignature
CBW[0] = 0x55;
CBW[1] = 0x53;
CBW[2] = 0x42;
CBW[3] = 0x53;

// dCBWDataTransferLength
CBW[8] = DataBufLen & 0x000000FF;
CBW[9] = (DataBufLen & 0x0000FF00) >> 8;
CBW[10] = (DataBufLen & 0x00FF0000) >> 16;
CBW[11] = (DataBufLen & 0xFF000000) >> 24;

// bmCBWFlags
if ((Dir == DATA_IN) && (DataBufLen != 0)) {
CBW[12] = 0x80;
} else {
CBW[12] = 0x00;
}

// bCBWCBLength
CBW[14] = 0x0c;

// CBWCB
memcpy(&CBW[15], pCBWCB, 12);

// Write CBW
#ifdef DEBUG_MSG
int i;
printf("\n");
printf("CBW=> ");
for (i = 0; i < 31; i++) {
printf("%02x ", CBW[i]);
}
printf("\n");
#endif

if (!BulkUSB_Write(31, CBW)) {
return 0;
}

if (DataBufLen > 0) {
// Data Phase
if (Dir == DATA_IN) {
if (!BulkUSB_Read(DataBufLen, pDataBuf)) {
return 0;
}
} else {
if (!BulkUSB_Write(DataBufLen, pDataBuf)) {
return 0;
}
}
}

#ifdef DEBUG_MSG
if (DataBufLen > 0) {
printf("DATA=> ");
for (i = 0; i < DataBufLen; i++) {
printf("%02X ", pDataBuf[i]);
if (i % 16 == 15) {
printf("\n");
}

}

if (DataBufLen % 16) {
printf("\n");
}
}
#endif

// Read CSW
if (!BulkUSB_Read(13, CSW)) {
return 0;
} else {

#ifdef DEBUG_MSG
int i;
printf("CSW=> ");
for (i = 0; i < 13; i++) {
printf("%02x ", CSW[i]);
}
printf("\n");
#endif
if (CSW[12] != 0x00) {
return 0;
} else {
return 1;
}
}
}

int
BulkUSB_TestUnitReady()
{
int r_value;

unsigned char CBWCB[12];

memset(CBWCB, 0x00, 12);

if (BulkUSB_ExecCBWCB(CBWCB, DATA_IN, NULL, 0)) {
return 1;
} else {
return 0;
}
}

int
BulkUSB_ReadCapacity(int *pLastLBA)
{
int r_value;

unsigned char CBWCB[12];
unsigned char ReadData[8];

memset(CBWCB, 0x00, 12);
memset(ReadData, 0x00, 8);

CBWCB[0] = 0x25;

if (BulkUSB_ExecCBWCB(CBWCB, DATA_IN, ReadData, 8)) {

*pLastLBA = ReadData[3];
*pLastLBA += ReadData[2] << 8;
*pLastLBA += ReadData[1] << 16;
*pLastLBA += ReadData[0] << 24;

return 1;
} else {
return 0;
}
}

int
BulkUSB_Inquiry(unsigned char *pInq)
{
int r_value;

unsigned char CBWCB[12];

memset(CBWCB, 0x00, 12);

CBWCB[0] = 0x12;

if (BulkUSB_ExecCBWCB(CBWCB, DATA_IN, pInq, 36)) {
return 1;
} else {
return 0;
}

}