Help with usb_bulk_read/write problem
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;
}
}