Ach, too quick.
> diff -urb
that should have been "diff -urbN". Sorry about that.
Am not going to send the diff once more. Below the new files.
---- raw_bulk.h ----
#ifndef _USB_STORAGE_RAW_BULK_H_
#define _USB_STORAGE_RAW_BULK_H_
/* usb bulk */
extern int usb_storage_send_control(
struct us_data *us, int pipe,
unsigned char request, unsigned char requesttype,
unsigned int value, unsigned int index,
unsigned char *xfer_data, unsigned int xfer_len);
extern int usb_storage_raw_bulk(
struct us_data *us, int direction,
unsigned char *data, unsigned int len, unsigned int *act_len);
extern int usb_storage_bulk_transport(
struct us_data *us, int direction,
unsigned char *data, unsigned int len, int use_sg);
/* scatter-gather */
extern unsigned char *us_copy_from_sgbuf(
unsigned char *content, int buflen,
int *index, int *offset, int use_sg);
extern unsigned char *us_copy_from_sgbuf_all(
unsigned char *content, int len, int use_sg);
extern void us_copy_to_sgbuf(
unsigned char *buffer, int buflen,
void *content, int *index, int *offset, int use_sg);
extern void us_copy_to_sgbuf_all(
unsigned char *buffer, int buflen,
void *content, int use_sg);
#endif
---- raw_bulk.c ----
/*
* Common routines for a handful of drivers.
* Unrelated to CF/SM - just USB stuff.
*
* This is mostly a thin layer on top of transport.c.
* It converts routines that return values like -ENOENT and -EPIPE
* into routines that return USB_STOR_TRANSPORT_ABORTED etc.
*
* There is also some debug printing here.
*/
#include "debug.h"
#include "transport.h"
#include "raw_bulk.h"
#ifdef CONFIG_USB_STORAGE_DEBUG
#define DEBUG_PRCT 12
#else
#define DEBUG_PRCT 0
#endif
/*
* Send a control message and wait for the response.
*
* us - the pointer to the us_data structure for the device to use
*
* request - the URB Setup Packet's first 6 bytes. The first byte always
* corresponds to the request type, and the second byte always corresponds
* to the request. The other 4 bytes do not correspond to value and index,
* since they are used in a custom way by the SCM protocol.
*
* xfer_data - a buffer from which to get, or to which to store, any data
* that gets send or received, respectively, with the URB. Even though
* it looks like we allocate a buffer in this code for the data, xfer_data
* must contain enough allocated space.
*
* xfer_len - the number of bytes to send or receive with the URB.
*
*/
int
usb_storage_send_control(struct us_data *us,
int pipe,
unsigned char request,
unsigned char requesttype,
unsigned int value,
unsigned int index,
unsigned char *xfer_data,
unsigned int xfer_len) {
int result;
// Send the URB to the device and wait for a response.
printk("usb_storage_send_control\n");
/* Why are request and request type reversed in this call? */
result = usb_stor_control_msg(us, pipe,
request, requesttype, value, index,
xfer_data, xfer_len);
printk("usb_stor_control_msg returns %d\n", result);
// Check the return code for the command.
if (result < 0) {
/* if the command was aborted, indicate that */
if (result == -ENOENT)
return USB_STOR_TRANSPORT_ABORTED;
/* a stall is a fatal condition from the device */
if (result == -EPIPE) {
US_DEBUGP("-- Stall on control pipe. Clearing\n");
result = usb_clear_halt(us->pusb_dev, pipe);
US_DEBUGP("-- usb_clear_halt() returns %d\n",
result);
return USB_STOR_TRANSPORT_FAILED;
}
/* Uh oh... serious problem here */
return USB_STOR_TRANSPORT_ERROR;
}
return USB_STOR_TRANSPORT_GOOD;
}
int
usb_storage_raw_bulk(struct us_data *us, int direction, unsigned char *data,
unsigned int len, unsigned int *act_len) {
int result;
int pipe;
if (direction == SCSI_DATA_READ)
pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
else
pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
result = usb_stor_bulk_msg(us, data, pipe, len, act_len);
/* if we stall, we need to clear it before we go on */
if (result == -EPIPE) {
US_DEBUGP("EPIPE: clearing endpoint halt for"
" pipe 0x%x, stalled at %d bytes\n",
pipe, *act_len);
usb_clear_halt(us->pusb_dev, pipe);
/* return US_BULK_TRANSFER_SHORT; */
}
if (result) {
/* -ENOENT -- we canceled this transfer */
if (result == -ENOENT) {
US_DEBUGP("raw_bulk(): transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
}
/* NAK - that means we've retried a few times already */
if (result == -ETIMEDOUT)
US_DEBUGP("raw_bulk(): device NAKed\n");
else if (result == -EOVERFLOW)
US_DEBUGP("raw_bulk(): babble/overflow\n");
else if (result == -ECONNRESET)
US_DEBUGP("raw_bulk(): asynchronous reset\n");
else if (result != -EPIPE)
US_DEBUGP("raw_bulk(): unknown error %d\n",
result);
return US_BULK_TRANSFER_FAILED;
}
if (*act_len != len) {
US_DEBUGP("Warning: Transferred only %d of %d bytes\n",
*act_len, len);
return US_BULK_TRANSFER_SHORT;
}
#if 0
US_DEBUGP("raw_bulk(): Transferred %s %d of %d bytes\n",
(direction == SCSI_DATA_READ) ? "in" : "out",
*act_len, len);
#endif
return US_BULK_TRANSFER_GOOD;
}
int
usb_storage_bulk_transport(struct us_data *us, int direction,
unsigned char *data, unsigned int len,
int use_sg) {
int result = USB_STOR_TRANSPORT_GOOD;
int transferred = 0;
int i;
struct scatterlist *sg;
unsigned int act_len;
if (len == 0)
return USB_STOR_TRANSPORT_GOOD;
#if DEBUG_PRCT
if (direction == SCSI_DATA_WRITE && !use_sg) {
char string[64];
/* Debug-print the first N bytes of the write transfer */
strcpy(string, "wr: ");
for (i=0; i<len && i<DEBUG_PRCT; i++) {
sprintf(string+strlen(string), "%02X ", data[i]);
if ((i%16) == 15) {
US_DEBUGP("%s\n", string);
strcpy(string, "wr: ");
}
}
if ((i%16)!=0)
US_DEBUGP("%s\n", string);
}
US_DEBUGP("SCM data %s transfer %d sg buffers %d\n",
(direction == SCSI_DATA_READ) ? "in" : "out",
len, use_sg);
#endif /* DEBUG_PRCT */
if (!use_sg)
result = usb_storage_raw_bulk(us, direction,
data, len, &act_len);
else {
sg = (struct scatterlist *)data;
for (i=0; i<use_sg && transferred<len; i++) {
unsigned char *buf;
unsigned int length;
buf = page_address(sg[i].page) + sg[i].offset;
length = len-transferred;
if (length > sg[i].length)
length = sg[i].length;
result = usb_storage_raw_bulk(us, direction,
buf, length, &act_len);
if (result != US_BULK_TRANSFER_GOOD)
break;
transferred += length;
}
}
#if DEBUG_PRCT
if (direction == SCSI_DATA_READ && !use_sg) {
char string[64];
/* Debug-print the first N bytes of the read transfer */
strcpy(string, "rd: ");
for (i=0; i<len && i<act_len && i<DEBUG_PRCT; i++) {
sprintf(string+strlen(string), "%02X ", data[i]);
if ((i%16) == 15) {
US_DEBUGP("%s\n", string);
strcpy(string, "rd: ");
}
}
if ((i%16)!=0)
US_DEBUGP("%s\n", string);
}
#endif /* DEBUG_PRCT */
return result;
}
/*
* The routines below convert scatter-gather to single buffer.
* Some drivers claim this is necessary.
* Nothing is done when use_sg is zero.
*/
/*
* Copy from scatter-gather buffer into a newly allocated single buffer,
* starting at a given index and offset.
* When done, update index and offset.
* Return a pointer to the single buffer.
*/
unsigned char *
us_copy_from_sgbuf(unsigned char *content, int len,
int *index, int *offset, int use_sg) {
struct scatterlist *sg;
unsigned char *buffer;
int transferred, i;
if (!use_sg)
return content;
sg = (struct scatterlist *)content;
buffer = kmalloc(len, GFP_NOIO);
if (buffer == NULL)
return NULL;
transferred = 0;
i = *index;
while (i < use_sg && transferred < len) {
unsigned char *ptr;
unsigned int length, room;
ptr = page_address(sg[i].page) + sg[i].offset + *offset;
room = sg[i].length - *offset;
length = len - transferred;
if (length > room)
length = room;
memcpy(buffer+transferred, ptr, length);
transferred += length;
*offset += length;
if (length == room) {
i++;
*offset = 0;
}
}
*index = i;
return buffer;
}
unsigned char *
us_copy_from_sgbuf_all(unsigned char *content, int len, int use_sg) {
int index, offset;
index = offset = 0;
return us_copy_from_sgbuf(content, len, &index, &offset, use_sg);
}
/*
* Copy from a single buffer into a scatter-gather buffer,
* starting at a given index and offset.
* When done, update index and offset.
*/
void
us_copy_to_sgbuf(unsigned char *buffer, int buflen,
void *content, int *index, int *offset, int use_sg) {
struct scatterlist *sg;
int i, transferred;
if (!use_sg)
return;
transferred = 0;
sg = content;
i = *index;
while (i < use_sg && transferred < buflen) {
unsigned char *ptr;
unsigned int length, room;
ptr = page_address(sg[i].page) + sg[i].offset + *offset;
room = sg[i].length - *offset;
length = buflen - transferred;
if (length > room)
length = room;
memcpy(ptr, buffer+transferred, length);
transferred += sg[i].length;
*offset += length;
if (length == room) {
i++;
*offset = 0;
}
}
*index = i;
}
void
us_copy_to_sgbuf_all(unsigned char *buffer, int buflen,
void *content, int use_sg) {
int index, offset;
index = offset = 0;
us_copy_to_sgbuf(buffer, buflen, content, &index, &offset, use_sg);
}
_______________________________________________________________
Don't miss the 2002 Sprint PCS Application Developer's Conference
August 25-28 in Las Vegas -- http://devcon.sprintpcs.com/adp/index.cfm
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel