add a fallback-to-genericusb mode to the generic scsi wrapper
git-svn-id: https://svn.code.sf.net/p/gphoto/code/trunk/libgphoto2@14828 67ed7778-7388-44ab-90cf-0a291f65f57c
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
/* sierra_usbwrap.c
|
||||
*
|
||||
* Copyright © 2002 Lutz Müller <lutz@users.sourceforge.net>
|
||||
* Copyright 2002 Lutz Müller <lutz@users.sourceforge.net>
|
||||
* Copyright 2012-2013 Marcus Meissner <marcus@jet.franken.de>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -123,7 +124,37 @@ cmdbyte (unsigned int type, unsigned char nr) {
|
||||
#define UW_PACKET_DATA ((uw4c_t){ 0x02, 0x00, 0xff, 0x9f })
|
||||
#define UW_PACKET_STAT ((uw4c_t){ 0x03, 0x00, 0xff, 0x9f })
|
||||
|
||||
#define UW_MAGIC_OUT ((uw4c_t){ 'U','S','B','C' })
|
||||
#define UW_MAGIC_IN ((uw4c_t){ 'U','S','B','S' })
|
||||
|
||||
#pragma pack(1)
|
||||
/* This is linux/include/linux/usb/storage.h, struct bulk_cb_wrap
|
||||
* 31 byte length */
|
||||
typedef struct
|
||||
{
|
||||
uw4c_t magic; /* The letters U S B C for packets sent to camera */
|
||||
uw32_t tag; /* The SCSI command tag */
|
||||
uw32_t rw_length; /* Length of data to be read or written next */
|
||||
unsigned char flags; /* in / out flag mostly */
|
||||
unsigned char lun; /* 0 here */
|
||||
unsigned char length; /* of the CDB... but 0x0c is used here in the traces */
|
||||
unsigned char cdb[16];
|
||||
} uw_header_t;
|
||||
|
||||
/*
|
||||
* This is the end response block from the camera looks like this:
|
||||
*
|
||||
* This is the generic bulk style USB Storage response block.
|
||||
*
|
||||
* linux/include/linux/usb/storage.h, struct bulk_cs_wrap */
|
||||
typedef struct
|
||||
{
|
||||
uw4c_t magic; /* The letters U S B S for packets from camera */
|
||||
uw32_t tag; /* A copy of whatever value the host made up */
|
||||
uw32_t residue; /* residual read? */
|
||||
char status; /* status byte */
|
||||
} uw_response_t;
|
||||
|
||||
/*
|
||||
* Data packet sent along with a UW_REQUEST_RDY:
|
||||
*/
|
||||
@@ -165,16 +196,6 @@ typedef struct
|
||||
uw32_t size; /* The size of data waiting to be sent by camera */
|
||||
} uw_size_t;
|
||||
|
||||
/*
|
||||
* The end of the response from the camera looks like this:
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uw4c_t magic; /* The letters U S B S for packets from camera */
|
||||
uw32_t sessionid; /* A copy of whatever value the host made up */
|
||||
char zero[5]; /* 00 00 00 00 00 */
|
||||
} uw_response_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char cmd;
|
||||
@@ -184,6 +205,99 @@ typedef struct
|
||||
} uw_scsicmd_t;
|
||||
#pragma pack()
|
||||
|
||||
static int ums_tag = 0x42424242;
|
||||
|
||||
static int
|
||||
scsi_wrap_cmd(
|
||||
GPPort *dev, int todev,
|
||||
char *cmd, unsigned int cmdlen,
|
||||
char *sense, unsigned int senselen,
|
||||
char *data, unsigned int size
|
||||
) {
|
||||
GPPortInfo info;
|
||||
GPPortType type;
|
||||
uw_header_t hdr;
|
||||
uw_response_t rsp;
|
||||
int ret;
|
||||
|
||||
ret = gp_port_get_info (dev, &info);
|
||||
if (ret != GP_OK) return ret;
|
||||
|
||||
ret = gp_port_info_get_type (info, &type);
|
||||
if (ret != GP_OK) return ret;
|
||||
|
||||
if (type == GP_PORT_USB_SCSI)
|
||||
/* just send it to the generic SCSI stack */
|
||||
return gp_port_send_scsi_cmd (
|
||||
dev, todev,
|
||||
cmd, cmdlen,
|
||||
sense, senselen,
|
||||
data, size
|
||||
);
|
||||
|
||||
/* Assuming plain USB, emulating SCSI ... */
|
||||
|
||||
memset(&hdr, 0, sizeof(hdr));
|
||||
hdr.magic = UW_MAGIC_OUT;
|
||||
hdr.tag = uw_value(ums_tag);
|
||||
ums_tag++;
|
||||
hdr.rw_length = uw_value(size);
|
||||
hdr.length = 12; /* seems to be always 12, even as we send 16 byte CDBs */
|
||||
hdr.flags = todev?0:(1<<7);
|
||||
hdr.lun = 0;
|
||||
|
||||
memcpy(hdr.cdb, cmd, cmdlen);
|
||||
|
||||
/* WRITE scsi header / cdb */
|
||||
if ((ret=gp_port_write(dev, (char*)&hdr, sizeof(hdr))) < GP_OK) {
|
||||
GP_DEBUG( "scsi_wrap_cmd *** FAILED to write scsi cmd" );
|
||||
return GP_ERROR_IO;
|
||||
}
|
||||
/* WRITE / READ data blob */
|
||||
if (todev) {
|
||||
if ((ret=gp_port_write(dev, (char*)data, size)) < GP_OK) {
|
||||
GP_DEBUG( "scsi_wrap_cmd *** FAILED to write scsi data" );
|
||||
return GP_ERROR_IO;
|
||||
}
|
||||
} else {
|
||||
if ((ret=gp_port_read(dev, (char*)data, size)) < GP_OK) {
|
||||
GP_DEBUG( "scsi_wrap_cmd *** FAILED to read scsi data" );
|
||||
return GP_ERROR_IO;
|
||||
}
|
||||
}
|
||||
|
||||
/* READ RESPONSE */
|
||||
memset(&rsp, 0, sizeof(rsp));
|
||||
|
||||
GP_DEBUG( "usb_wrap_OK" );
|
||||
if ((ret = gp_port_read(dev, (char*)&rsp, sizeof(rsp))) != sizeof(rsp)) {
|
||||
gp_log (GP_LOG_DEBUG, GP_MODULE, "scsi_wrap_cmd *** FAILED (%d vs %d bytes)", (int)sizeof(rsp), ret );
|
||||
if (ret < GP_OK)
|
||||
return ret;
|
||||
return GP_ERROR;
|
||||
}
|
||||
if ( !UW_EQUAL(rsp.magic, UW_MAGIC_IN) ||
|
||||
!UW_EQUAL(rsp.tag, hdr.tag))
|
||||
{
|
||||
GP_DEBUG( "scsi_wrap_cmd wrong session *** FAILED" );
|
||||
return GP_ERROR;
|
||||
}
|
||||
/*
|
||||
* 32bit residual length (0) and 8 bit status (0) are good.
|
||||
*/
|
||||
if ( rsp.residue.c1 != 0 ||
|
||||
rsp.residue.c2 != 0 ||
|
||||
rsp.residue.c3 != 0 ||
|
||||
rsp.residue.c4 != 0 ||
|
||||
rsp.status != 0) {
|
||||
GP_DEBUG( "Error: scsi_wrap_cmd - residual non-0 or status %x", rsp.status);
|
||||
return GP_ERROR;
|
||||
}
|
||||
return GP_OK;
|
||||
}
|
||||
|
||||
#define gp_port_send_scsi_cmd scsi_wrap_cmd
|
||||
|
||||
static int
|
||||
usb_wrap_RDY(gp_port* dev, unsigned int type)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user